From bdc78737278ee77fdcbccaee5b6f7eda4e0e7602 Mon Sep 17 00:00:00 2001 From: Stefan Schmidt Date: Fri, 29 May 2015 10:51:25 +0200 Subject: ieee802154/atusb: Add function for partial register writes With this function we can set individual bits in the registers if needed. With the old SR_VALUE macro we could only set one bit in the register which was ok for some scenarios but not for all. With this subreg write function we can now set more bits defined by the mask while not touching the rest. We start using it for the current SR_VALUE use case and will use it more in upcoming patches. Signed-off-by: Stefan Schmidt Reviewed-by: Varka Bhadram Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/atusb.c | 45 +++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 18 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/atusb.c b/drivers/net/ieee802154/atusb.c index 5b6bb9adf9ae..95d42205fd53 100644 --- a/drivers/net/ieee802154/atusb.c +++ b/drivers/net/ieee802154/atusb.c @@ -58,17 +58,6 @@ struct atusb { uint8_t tx_ack_seq; /* current TX ACK sequence number */ }; -/* at86rf230.h defines values as tuples. We use the more - * traditional style of having registers and or-able values. SR_REG extracts - * the register number. SR_VALUE uses the shift to prepare a value accordingly. - */ - -#define __SR_REG(reg, mask, shift) (reg) -#define SR_REG(sr) __SR_REG(sr) - -#define __SR_VALUE(reg, mask, shift, val) ((val) << (shift)) -#define SR_VALUE(sr, val) __SR_VALUE(sr, (val)) - /* ----- USB commands without data ----------------------------------------- */ /* To reduce the number of error checks in the code, we record the first error @@ -130,6 +119,30 @@ static int atusb_read_reg(struct atusb *atusb, uint8_t reg) return ret >= 0 ? value : ret; } +static int atusb_write_subreg(struct atusb *atusb, uint8_t reg, uint8_t mask, + uint8_t shift, uint8_t value) +{ + struct usb_device *usb_dev = atusb->usb_dev; + uint8_t orig, tmp; + int ret = 0; + + dev_dbg(&usb_dev->dev, "atusb_write_subreg: 0x%02x <- 0x%02x\n", + reg, value); + + orig = atusb_read_reg(atusb, reg); + + /* Write the value only into that part of the register which is allowed + * by the mask. All other bits stay as before. + */ + tmp = orig & ~mask; + tmp |= (value << shift) & mask; + + if (tmp != orig) + ret = atusb_write_reg(atusb, reg, tmp); + + return ret; +} + static int atusb_get_and_clear_error(struct atusb *atusb) { int err = atusb->err; @@ -376,7 +389,6 @@ static int atusb_set_hw_addr_filt(struct ieee802154_hw *hw, { struct atusb *atusb = hw->priv; struct device *dev = &atusb->usb_dev->dev; - uint8_t reg; if (changed & IEEE802154_AFILT_SADDR_CHANGED) { u16 addr = le16_to_cpu(filt->short_addr); @@ -406,12 +418,10 @@ static int atusb_set_hw_addr_filt(struct ieee802154_hw *hw, if (changed & IEEE802154_AFILT_PANC_CHANGED) { dev_vdbg(dev, "atusb_set_hw_addr_filt called for panc change\n"); - reg = atusb_read_reg(atusb, SR_REG(SR_AACK_I_AM_COORD)); if (filt->pan_coord) - reg |= SR_VALUE(SR_AACK_I_AM_COORD, 1); + atusb_write_subreg(atusb, SR_AACK_I_AM_COORD, 1); else - reg &= ~SR_VALUE(SR_AACK_I_AM_COORD, 1); - atusb_write_reg(atusb, SR_REG(SR_AACK_I_AM_COORD), reg); + atusb_write_subreg(atusb, SR_AACK_I_AM_COORD, 0); } return atusb_get_and_clear_error(atusb); @@ -622,8 +632,7 @@ static int atusb_probe(struct usb_interface *interface, * http://www.jennic.com/download_file.php?supportFile=JN-AN-1035%20Calculating%20802-15-4%20Data%20Rates-1v0.pdf */ - atusb_write_reg(atusb, - SR_REG(SR_RX_SAFE_MODE), SR_VALUE(SR_RX_SAFE_MODE, 1)); + atusb_write_subreg(atusb, SR_RX_SAFE_MODE, 1); #endif atusb_write_reg(atusb, RG_IRQ_MASK, 0xff); -- cgit v1.2.3 From 8702cb0f21905a2a96f61c5106a2c42d41c17999 Mon Sep 17 00:00:00 2001 From: Stefan Schmidt Date: Fri, 29 May 2015 10:51:26 +0200 Subject: ieee802154/atusb: Add .set_txpower operation to the driver Atusb uses the at86rf231 transceiver so we can use the same calculation for txpower settings for it. Signed-off-by: Stefan Schmidt Reviewed-by: Varka Bhadram Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/atusb.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/atusb.c b/drivers/net/ieee802154/atusb.c index 95d42205fd53..9805ebeccd75 100644 --- a/drivers/net/ieee802154/atusb.c +++ b/drivers/net/ieee802154/atusb.c @@ -453,6 +453,26 @@ static void atusb_stop(struct ieee802154_hw *hw) atusb_get_and_clear_error(atusb); } +#define ATUSB_MAX_TX_POWERS 0xF +static const s32 atusb_powers[ATUSB_MAX_TX_POWERS + 1] = { + 300, 280, 230, 180, 130, 70, 0, -100, -200, -300, -400, -500, -700, + -900, -1200, -1700, +}; + +static int +atusb_set_txpower(struct ieee802154_hw *hw, s32 mbm) +{ + struct atusb *atusb = hw->priv; + u32 i; + + for (i = 0; i < hw->phy->supported.tx_powers_size; i++) { + if (hw->phy->supported.tx_powers[i] == mbm) + return atusb_write_subreg(atusb, SR_TX_PWR_23X, i); + } + + return -EINVAL; +} + static struct ieee802154_ops atusb_ops = { .owner = THIS_MODULE, .xmit_async = atusb_xmit, @@ -461,6 +481,7 @@ static struct ieee802154_ops atusb_ops = { .start = atusb_start, .stop = atusb_stop, .set_hw_addr_filt = atusb_set_hw_addr_filt, + .set_txpower = atusb_set_txpower, }; /* ----- Firmware and chip version information ----------------------------- */ @@ -581,9 +602,14 @@ static int atusb_probe(struct usb_interface *interface, hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AFILT | IEEE802154_HW_AACK; + hw->phy->flags = WPAN_PHY_FLAG_TXPOWER; + hw->phy->current_page = 0; hw->phy->current_channel = 11; /* reset default */ hw->phy->supported.channels[0] = 0x7FFF800; + hw->phy->supported.tx_powers = atusb_powers; + hw->phy->supported.tx_powers_size = ARRAY_SIZE(atusb_powers); + hw->phy->transmit_power = hw->phy->supported.tx_powers[0]; ieee802154_random_extended_addr(&hw->phy->perm_extended_addr); atusb_command(atusb, ATUSB_RF_RESET, 0); -- cgit v1.2.3 From c61c9bd81bea4e2c86058123e8d221a40b9c58a3 Mon Sep 17 00:00:00 2001 From: Stefan Schmidt Date: Fri, 29 May 2015 10:51:27 +0200 Subject: ieee802154/atusb: Add .set_promiscuous_mode driver operation Allow monitor mode operation with disabled AACK in hardware. Signed-off-by: Stefan Schmidt Reviewed-by: Varka Bhadram Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/atusb.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/atusb.c b/drivers/net/ieee802154/atusb.c index 9805ebeccd75..3d25678dfd95 100644 --- a/drivers/net/ieee802154/atusb.c +++ b/drivers/net/ieee802154/atusb.c @@ -473,6 +473,33 @@ atusb_set_txpower(struct ieee802154_hw *hw, s32 mbm) return -EINVAL; } +static int +atusb_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on) +{ + struct atusb *atusb = hw->priv; + int ret; + + if (on) { + ret = atusb_write_subreg(atusb, SR_AACK_DIS_ACK, 1); + if (ret < 0) + return ret; + + ret = atusb_write_subreg(atusb, SR_AACK_PROM_MODE, 1); + if (ret < 0) + return ret; + } else { + ret = atusb_write_subreg(atusb, SR_AACK_PROM_MODE, 0); + if (ret < 0) + return ret; + + ret = atusb_write_subreg(atusb, SR_AACK_DIS_ACK, 0); + if (ret < 0) + return ret; + } + + return 0; +} + static struct ieee802154_ops atusb_ops = { .owner = THIS_MODULE, .xmit_async = atusb_xmit, @@ -482,6 +509,7 @@ static struct ieee802154_ops atusb_ops = { .stop = atusb_stop, .set_hw_addr_filt = atusb_set_hw_addr_filt, .set_txpower = atusb_set_txpower, + .set_promiscuous_mode = atusb_set_promiscuous_mode, }; /* ----- Firmware and chip version information ----------------------------- */ @@ -600,7 +628,7 @@ static int atusb_probe(struct usb_interface *interface, hw->parent = &usb_dev->dev; hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AFILT | - IEEE802154_HW_AACK; + IEEE802154_HW_AACK | IEEE802154_HW_PROMISCUOUS; hw->phy->flags = WPAN_PHY_FLAG_TXPOWER; -- cgit v1.2.3 From aad1b0b5d3e0e4cdadd695b7188873ba614ca4ef Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Fri, 29 May 2015 10:56:54 +0530 Subject: cc2520: fix in default tx power setting Initially we dont have the tx power settings from the user-space. Now we have the support for seeting the tx power level. So lets use the default tx power setting for the radio. Signed-off-by: Varka Bhadram Cc: Brad Campbell Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/cc2520.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index 84b28a05c5a1..ea280d437ca1 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -782,10 +782,6 @@ static int cc2520_hw_init(struct cc2520_private *priv) * http://www.ti.com/lit/an/swra229a/swra229a.pdf */ if (pdata.amplified) { - ret = cc2520_write_register(priv, CC2520_TXPOWER, 0xF9); - if (ret) - goto err_ret; - ret = cc2520_write_register(priv, CC2520_AGCCTRL1, 0x16); if (ret) goto err_ret; @@ -806,10 +802,6 @@ static int cc2520_hw_init(struct cc2520_private *priv) if (ret) goto err_ret; } else { - ret = cc2520_write_register(priv, CC2520_TXPOWER, 0xF7); - if (ret) - goto err_ret; - ret = cc2520_write_register(priv, CC2520_AGCCTRL1, 0x11); if (ret) goto err_ret; -- cgit v1.2.3 From 1a1bc59c5f7657387d1a4b45d63248fed55ab88c Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Fri, 29 May 2015 10:56:55 +0530 Subject: cc2520: fix CC2591 handling This patch changes tha way of handling of cc2591-cc2520 combination by moving amplified variable from platform data to private data. This will be useful in other sections like tx power support. Signed-off-by: Varka Bhadram Cc: Brad Campbell Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/cc2520.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index ea280d437ca1..0d9353756598 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -196,6 +196,7 @@ struct cc2520_private { u8 *buf; /* SPI TX/Rx data buffer */ struct mutex buffer_mutex; /* SPI buffer mutex */ bool is_tx; /* Flag for sync b/w Tx and Rx */ + bool amplified; /* Flag for CC2591 */ int fifo_pin; /* FIFO GPIO pin number */ struct work_struct fifop_irqwork;/* Workqueue for FIFOP */ spinlock_t lock; /* Lock for is_tx*/ @@ -738,7 +739,9 @@ static int cc2520_get_platform_data(struct spi_device *spi, pdata->vreg = of_get_named_gpio(np, "vreg-gpio", 0); pdata->reset = of_get_named_gpio(np, "reset-gpio", 0); - pdata->amplified = of_property_read_bool(np, "amplified"); + /* CC2591 front end for CC2520 */ + if (of_property_read_bool(np, "amplified")) + priv->amplified = true; return 0; } @@ -781,7 +784,7 @@ static int cc2520_hw_init(struct cc2520_private *priv) * amplifier. See section 8 page 17 of TI application note AN065. * http://www.ti.com/lit/an/swra229a/swra229a.pdf */ - if (pdata.amplified) { + if (priv->amplified) { ret = cc2520_write_register(priv, CC2520_AGCCTRL1, 0x16); if (ret) goto err_ret; @@ -896,6 +899,9 @@ static int cc2520_probe(struct spi_device *spi) spin_lock_init(&priv->lock); init_completion(&priv->tx_complete); + /* Assumption that CC2591 is not connected */ + priv->amplified = false; + /* Request all the gpio's */ if (!gpio_is_valid(pdata.fifo)) { dev_err(&spi->dev, "fifo gpio is not valid\n"); -- cgit v1.2.3 From e10c1674e31558807fcccfbf3dbebbc1cad9099c Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Fri, 29 May 2015 10:56:56 +0530 Subject: cc2520: add set transmit power setting support This patch adds support for seeting tx power values for cc2520 and also for the combination of CC2520-CC2591. Signed-off-by: Varka Bhadram Cc: Brad Campbell Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/cc2520.c | 102 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index 0d9353756598..36a4f312cc7c 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -629,6 +629,97 @@ cc2520_filter(struct ieee802154_hw *hw, return 0; } +static inline int cc2520_set_tx_power(struct cc2520_private *priv, s32 mbm) +{ + u8 power; + + switch (mbm) { + case 500: + power = 0xF7; + break; + case 300: + power = 0xF2; + break; + case 200: + power = 0xAB; + break; + case 100: + power = 0x13; + break; + case 0: + power = 0x32; + break; + case -200: + power = 0x81; + break; + case -400: + power = 0x88; + break; + case -700: + power = 0x2C; + break; + case -1800: + power = 0x03; + break; + default: + return -EINVAL; + } + + return cc2520_write_register(priv, CC2520_TXPOWER, power); +} + +static inline int cc2520_cc2591_set_tx_power(struct cc2520_private *priv, + s32 mbm) +{ + u8 power; + + switch (mbm) { + case 1700: + power = 0xF9; + break; + case 1600: + power = 0xF0; + break; + case 1400: + power = 0xA0; + break; + case 1100: + power = 0x2C; + break; + case -100: + power = 0x03; + break; + case -800: + power = 0x01; + break; + default: + return -EINVAL; + } + + return cc2520_write_register(priv, CC2520_TXPOWER, power); +} + +#define CC2520_MAX_TX_POWERS 0x8 +static const s32 cc2520_powers[CC2520_MAX_TX_POWERS + 1] = { + 500, 300, 200, 100, 0, -200, -400, -700, -1800, +}; + +#define CC2520_CC2591_MAX_TX_POWERS 0x5 +static const s32 cc2520_cc2591_powers[CC2520_CC2591_MAX_TX_POWERS + 1] = { + 1700, 1600, 1400, 1100, -100, -800, +}; + +static int +cc2520_set_txpower(struct ieee802154_hw *hw, s32 mbm) +{ + struct cc2520_private *priv = hw->priv; + + if (!priv->amplified) + return cc2520_set_tx_power(priv, mbm); + + return cc2520_cc2591_set_tx_power(priv, mbm); +} + static const struct ieee802154_ops cc2520_ops = { .owner = THIS_MODULE, .start = cc2520_start, @@ -637,6 +728,7 @@ static const struct ieee802154_ops cc2520_ops = { .ed = cc2520_ed, .set_channel = cc2520_set_channel, .set_hw_addr_filt = cc2520_filter, + .set_txpower = cc2520_set_txpower, }; static int cc2520_register(struct cc2520_private *priv) @@ -658,6 +750,16 @@ static int cc2520_register(struct cc2520_private *priv) priv->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK | IEEE802154_HW_AFILT; + priv->hw->phy->flags = WPAN_PHY_FLAG_TXPOWER; + + if (!priv->amplified) { + priv->hw->phy->supported.tx_powers = cc2520_powers; + priv->hw->phy->supported.tx_powers_size = ARRAY_SIZE(cc2520_powers); + } else { + priv->hw->phy->supported.tx_powers = cc2520_cc2591_powers; + priv->hw->phy->supported.tx_powers_size = ARRAY_SIZE(cc2520_cc2591_powers); + } + dev_vdbg(&priv->spi->dev, "registered cc2520\n"); ret = ieee802154_register_hw(priv->hw); if (ret) -- cgit v1.2.3 From 322fe2d1beb7b381640999b48a7fb136e0870bb3 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Fri, 29 May 2015 10:56:57 +0530 Subject: cc2520: update initial transmit power value CC2520 has the default 0dBm transmit power level on reset. This patch update initial value of transmit power with 0dBm value. Signed-off-by: Varka Bhadram Cc: Brad Campbell Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/cc2520.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index 36a4f312cc7c..2384c286163f 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -755,9 +755,11 @@ static int cc2520_register(struct cc2520_private *priv) if (!priv->amplified) { priv->hw->phy->supported.tx_powers = cc2520_powers; priv->hw->phy->supported.tx_powers_size = ARRAY_SIZE(cc2520_powers); + priv->hw->phy->transmit_power = priv->hw->phy->supported.tx_powers[4]; } else { priv->hw->phy->supported.tx_powers = cc2520_cc2591_powers; priv->hw->phy->supported.tx_powers_size = ARRAY_SIZE(cc2520_cc2591_powers); + priv->hw->phy->transmit_power = priv->hw->phy->supported.tx_powers[0]; } dev_vdbg(&priv->spi->dev, "registered cc2520\n"); -- cgit v1.2.3 From d6d244d4df91ee4b468233050542c7482d705e69 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Fri, 29 May 2015 10:56:58 +0530 Subject: cc2520: update current channel This patch updates the current channel to 11. This is the default value on reset. Signed-off-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/cc2520.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index 2384c286163f..8141353221a1 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -762,6 +762,8 @@ static int cc2520_register(struct cc2520_private *priv) priv->hw->phy->transmit_power = priv->hw->phy->supported.tx_powers[0]; } + priv->hw->phy->current_channel = 11; + dev_vdbg(&priv->spi->dev, "registered cc2520\n"); ret = ieee802154_register_hw(priv->hw); if (ret) -- cgit v1.2.3 From ed65963ba0a2bdc330b1d7183f930d1c6a0a6685 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sat, 6 Jun 2015 17:30:46 +0200 Subject: mac802154: remove unneeded vif struct This patch removes the virtual interface structure from sub if data struct, because it isn't used anywhere. This structure could be useful for give per interface information at softmac driver layer. Nevertheless there exist no use case currently and it contains the interface type information currently. This information is also stored inside wpan dev which is now used to check on the wpan dev interface type. Signed-off-by: Alexander Aring Reviewed-by: Varka Bhadram Acked-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 1 - drivers/net/ieee802154/cc2520.c | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 2f25a5ed8247..6e20e9c94b3c 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1602,7 +1602,6 @@ static int at86rf230_probe(struct spi_device *spi) lp->spi = spi; lp->slp_tr = slp_tr; hw->parent = &spi->dev; - hw->vif_data_size = sizeof(*lp); ieee802154_random_extended_addr(&hw->phy->perm_extended_addr); lp->regmap = devm_regmap_init_spi(spi, &at86rf230_regmap_spi_config); diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index 8141353221a1..a8bafd6bd5e4 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -742,7 +742,6 @@ static int cc2520_register(struct cc2520_private *priv) priv->hw->priv = priv; priv->hw->parent = &priv->spi->dev; priv->hw->extra_tx_headroom = 0; - priv->hw->vif_data_size = sizeof(*priv); ieee802154_random_extended_addr(&priv->hw->phy->perm_extended_addr); /* We do support only 2.4 Ghz */ -- cgit v1.2.3 From f265be3d124a5b62e5a339685b6cfaa0292f1250 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sat, 6 Jun 2015 17:30:48 +0200 Subject: mac802154: remove aack hw flag This patch removes the hardware auto acknowdledge flag which indicates that the transceiver supports this handling. This flag is never evaluated inside mac802154 and all transceivers should support this handling by default per hardware. Suggested-by: Lennert Buytenhek Cc: Alan Ott Signed-off-by: Alexander Aring Reviewed-by: Varka Bhadram Acked-by: Stefan Schmidt Acked-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 2 +- drivers/net/ieee802154/atusb.c | 2 +- drivers/net/ieee802154/cc2520.c | 3 +-- drivers/net/ieee802154/mrf24j40.c | 3 +-- 4 files changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 6e20e9c94b3c..1bf86d2df23f 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1443,7 +1443,7 @@ at86rf230_detect_device(struct at86rf230_local *lp) return -EINVAL; } - lp->hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AACK | + lp->hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_CSMA_PARAMS | IEEE802154_HW_FRAME_RETRIES | IEEE802154_HW_AFILT | IEEE802154_HW_PROMISCUOUS; diff --git a/drivers/net/ieee802154/atusb.c b/drivers/net/ieee802154/atusb.c index 3d25678dfd95..80dfc725b8dc 100644 --- a/drivers/net/ieee802154/atusb.c +++ b/drivers/net/ieee802154/atusb.c @@ -628,7 +628,7 @@ static int atusb_probe(struct usb_interface *interface, hw->parent = &usb_dev->dev; hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AFILT | - IEEE802154_HW_AACK | IEEE802154_HW_PROMISCUOUS; + IEEE802154_HW_PROMISCUOUS; hw->phy->flags = WPAN_PHY_FLAG_TXPOWER; diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index a8bafd6bd5e4..15f263cfece5 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -746,8 +746,7 @@ static int cc2520_register(struct cc2520_private *priv) /* We do support only 2.4 Ghz */ priv->hw->phy->supported.channels[0] = 0x7FFF800; - priv->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK | - IEEE802154_HW_AFILT; + priv->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AFILT; priv->hw->phy->flags = WPAN_PHY_FLAG_TXPOWER; diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c index f2a1bd122a74..99c767695c7b 100644 --- a/drivers/net/ieee802154/mrf24j40.c +++ b/drivers/net/ieee802154/mrf24j40.c @@ -751,8 +751,7 @@ static int mrf24j40_probe(struct spi_device *spi) devrec->hw->priv = devrec; devrec->hw->parent = &devrec->spi->dev; devrec->hw->phy->supported.channels[0] = CHANNEL_MASK; - devrec->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK | - IEEE802154_HW_AFILT; + devrec->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AFILT; dev_dbg(printdev(devrec), "registered mrf24j40\n"); ret = ieee802154_register_hw(devrec->hw); -- cgit v1.2.3 From e5719b661a978f7d23042c140979351951f970bb Mon Sep 17 00:00:00 2001 From: Stefan Schmidt Date: Tue, 9 Jun 2015 10:52:26 +0200 Subject: ieee802154/mrf24j40: make sure we do not override return values If we run into an error during rx we set the the error code in ret, but override it afterwards. Using a different variable for the extra case avoids this situation. CID: 1226982, 1226983 Signed-off-by: Stefan Schmidt Cc: Alan Ott Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/mrf24j40.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c index 99c767695c7b..2549760e039f 100644 --- a/drivers/net/ieee802154/mrf24j40.c +++ b/drivers/net/ieee802154/mrf24j40.c @@ -533,6 +533,7 @@ static int mrf24j40_handle_rx(struct mrf24j40 *devrec) u8 lqi = 0; u8 val; int ret = 0; + int ret2; struct sk_buff *skb; /* Turn off reception of packets off the air. This prevents the @@ -569,9 +570,9 @@ static int mrf24j40_handle_rx(struct mrf24j40 *devrec) out: /* Turn back on reception of packets off the air. */ - ret = read_short_reg(devrec, REG_BBREG1, &val); - if (ret) - return ret; + ret2 = read_short_reg(devrec, REG_BBREG1, &val); + if (ret2) + return ret2; val &= ~0x4; /* Clear RXDECINV */ write_short_reg(devrec, REG_BBREG1, val); -- cgit v1.2.3 From c9d442038ef729549e1fd14ff1d61d0d3a7f0560 Mon Sep 17 00:00:00 2001 From: Stefan Schmidt Date: Tue, 9 Jun 2015 11:49:27 +0200 Subject: ieee802154: cc2520: check for return values in cc2520_filter() neither ram nor register write return values have been checked here. Checking both now. Assign ret with 0 as all other assignments are inside if blocks and might not happen before we return ret. CID: 1230469 Signed-off-by: Stefan Schmidt Acked-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/cc2520.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index 15f263cfece5..b6fc29579667 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -590,22 +590,23 @@ cc2520_filter(struct ieee802154_hw *hw, struct ieee802154_hw_addr_filt *filt, unsigned long changed) { struct cc2520_private *priv = hw->priv; + int ret = 0; if (changed & IEEE802154_AFILT_PANID_CHANGED) { u16 panid = le16_to_cpu(filt->pan_id); dev_vdbg(&priv->spi->dev, "cc2520_filter called for pan id\n"); - cc2520_write_ram(priv, CC2520RAM_PANID, - sizeof(panid), (u8 *)&panid); + ret = cc2520_write_ram(priv, CC2520RAM_PANID, + sizeof(panid), (u8 *)&panid); } if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) { dev_vdbg(&priv->spi->dev, "cc2520_filter called for IEEE addr\n"); - cc2520_write_ram(priv, CC2520RAM_IEEEADDR, - sizeof(filt->ieee_addr), - (u8 *)&filt->ieee_addr); + ret = cc2520_write_ram(priv, CC2520RAM_IEEEADDR, + sizeof(filt->ieee_addr), + (u8 *)&filt->ieee_addr); } if (changed & IEEE802154_AFILT_SADDR_CHANGED) { @@ -613,20 +614,22 @@ cc2520_filter(struct ieee802154_hw *hw, dev_vdbg(&priv->spi->dev, "cc2520_filter called for saddr\n"); - cc2520_write_ram(priv, CC2520RAM_SHORTADDR, - sizeof(addr), (u8 *)&addr); + ret = cc2520_write_ram(priv, CC2520RAM_SHORTADDR, + sizeof(addr), (u8 *)&addr); } if (changed & IEEE802154_AFILT_PANC_CHANGED) { dev_vdbg(&priv->spi->dev, "cc2520_filter called for panc change\n"); if (filt->pan_coord) - cc2520_write_register(priv, CC2520_FRMFILT0, 0x02); + ret = cc2520_write_register(priv, CC2520_FRMFILT0, + 0x02); else - cc2520_write_register(priv, CC2520_FRMFILT0, 0x00); + ret = cc2520_write_register(priv, CC2520_FRMFILT0, + 0x00); } - return 0; + return ret; } static inline int cc2520_set_tx_power(struct cc2520_private *priv, s32 mbm) -- cgit v1.2.3 From 9ff19e6f44e370d9ac20c2cc677724e44d76f2c6 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sat, 13 Jun 2015 22:15:53 +0200 Subject: at86rf230: use level high as fallback default This patch use high level interrupt type as fallback handling when no irq type is given. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 1bf86d2df23f..25e1edecc24b 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1633,7 +1633,7 @@ static int at86rf230_probe(struct spi_device *spi) irq_type = irq_get_trigger_type(spi->irq); if (!irq_type) - irq_type = IRQF_TRIGGER_RISING; + irq_type = IRQF_TRIGGER_HIGH; rc = devm_request_irq(&spi->dev, spi->irq, at86rf230_isr, IRQF_SHARED | irq_type, dev_name(&spi->dev), lp); -- cgit v1.2.3 From e6f7ed9dc1164c2f20bd984e251cf4dd5ff61d2c Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sat, 13 Jun 2015 22:15:54 +0200 Subject: at86rf230: add support for sleep state This patch adds support for sleep state when between stop and start period. In this period the transceiver isn't used by the subsystem, in this time we disable the irq and going into the sleep state. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 25e1edecc24b..6b31f4708122 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -47,6 +47,8 @@ struct at86rf2xx_chip_data { u16 t_reset_to_off; u16 t_off_to_aack; u16 t_off_to_tx_on; + u16 t_off_to_sleep; + u16 t_sleep_to_off; u16 t_frame; u16 t_p_ack; int rssi_base_val; @@ -869,13 +871,33 @@ at86rf230_ed(struct ieee802154_hw *hw, u8 *level) static int at86rf230_start(struct ieee802154_hw *hw) { + struct at86rf230_local *lp = hw->priv; + + if (gpio_is_valid(lp->slp_tr)) { + gpio_set_value(lp->slp_tr, 0); + usleep_range(lp->data->t_sleep_to_off, + lp->data->t_sleep_to_off + 100); + } + + enable_irq(lp->spi->irq); + return at86rf230_sync_state_change(hw->priv, STATE_RX_AACK_ON); } static void at86rf230_stop(struct ieee802154_hw *hw) { + struct at86rf230_local *lp = hw->priv; + at86rf230_sync_state_change(hw->priv, STATE_FORCE_TRX_OFF); + + disable_irq(lp->spi->irq); + + if (gpio_is_valid(lp->slp_tr)) { + gpio_set_value(lp->slp_tr, 1); + usleep_range(lp->data->t_off_to_sleep, + lp->data->t_off_to_sleep + 10); + } } static int @@ -1241,6 +1263,8 @@ static struct at86rf2xx_chip_data at86rf233_data = { .t_reset_to_off = 26, .t_off_to_aack = 80, .t_off_to_tx_on = 80, + .t_off_to_sleep = 35, + .t_sleep_to_off = 210, .t_frame = 4096, .t_p_ack = 545, .rssi_base_val = -91, @@ -1254,6 +1278,8 @@ static struct at86rf2xx_chip_data at86rf231_data = { .t_reset_to_off = 37, .t_off_to_aack = 110, .t_off_to_tx_on = 110, + .t_off_to_sleep = 35, + .t_sleep_to_off = 380, .t_frame = 4096, .t_p_ack = 545, .rssi_base_val = -91, @@ -1267,6 +1293,8 @@ static struct at86rf2xx_chip_data at86rf212_data = { .t_reset_to_off = 26, .t_off_to_aack = 200, .t_off_to_tx_on = 200, + .t_off_to_sleep = 35, + .t_sleep_to_off = 380, .t_frame = 4096, .t_p_ack = 545, .rssi_base_val = -100, @@ -1640,6 +1668,16 @@ static int at86rf230_probe(struct spi_device *spi) if (rc) goto free_dev; + /* disable_irq by default and wait for starting hardware */ + disable_irq(spi->irq); + + /* going into sleep by default */ + if (gpio_is_valid(slp_tr)) { + gpio_set_value(slp_tr, 1); + usleep_range(lp->data->t_off_to_sleep, + lp->data->t_off_to_sleep + 10); + } + rc = ieee802154_register_hw(lp->hw); if (rc) goto free_dev; -- cgit v1.2.3 From 789a99ecb9cb700eb8f07b9d106b99e705e99471 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 14 Jun 2015 16:48:44 +0200 Subject: fakelb: add xmit_async after stop testcase This patch adds a suspended testcase into the xmit_async functionality. In the hope that we can found race conditions when xmit_async is called after an ieee802154_ops stop. This should never happen. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/fakelb.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c index 9d0da4ec3e8c..860d4aed8274 100644 --- a/drivers/net/ieee802154/fakelb.c +++ b/drivers/net/ieee802154/fakelb.c @@ -41,6 +41,8 @@ struct fakelb_phy { u8 page; u8 channel; + bool suspended; + struct list_head list; struct list_head list_ifup; }; @@ -69,6 +71,7 @@ static int fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) struct fakelb_phy *current_phy = hw->priv, *phy; read_lock_bh(&fakelb_ifup_phys_lock); + WARN_ON(current_phy->suspended); list_for_each_entry(phy, &fakelb_ifup_phys, list_ifup) { if (current_phy == phy) continue; @@ -92,6 +95,7 @@ static int fakelb_hw_start(struct ieee802154_hw *hw) struct fakelb_phy *phy = hw->priv; write_lock_bh(&fakelb_ifup_phys_lock); + phy->suspended = false; list_add(&phy->list_ifup, &fakelb_ifup_phys); write_unlock_bh(&fakelb_ifup_phys_lock); @@ -103,6 +107,7 @@ static void fakelb_hw_stop(struct ieee802154_hw *hw) struct fakelb_phy *phy = hw->priv; write_lock_bh(&fakelb_ifup_phys_lock); + phy->suspended = true; list_del(&phy->list_ifup); write_unlock_bh(&fakelb_ifup_phys_lock); } -- cgit v1.2.3 From cbe6234689b07f5d1ecf2281573591ca4211a5cf Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 16 Jun 2015 11:07:42 +0200 Subject: at86rf230: fix phy settings while sleeping While in sleep state then we can't access the at86rf2xx registers. This patch checks if the transceiver is in sleep state before sending spi messages via regmap. Regmap is used on every driver ops callback except for receive and xmit handling, but while receive and xmit handling the phy should not be inside the sleep state. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 88 +++++++++++++++++++++++++++++--------- 1 file changed, 68 insertions(+), 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 6b31f4708122..b839bbd4ff69 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -90,6 +90,7 @@ struct at86rf230_local { struct at86rf2xx_chip_data *data; struct regmap *regmap; int slp_tr; + bool sleep; struct completion state_complete; struct at86rf230_state_change state; @@ -114,18 +115,66 @@ at86rf230_async_state_change(struct at86rf230_local *lp, const u8 state, void (*complete)(void *context), const bool irq_enable); +static inline void +at86rf230_sleep(struct at86rf230_local *lp) +{ + if (gpio_is_valid(lp->slp_tr)) { + gpio_set_value(lp->slp_tr, 1); + usleep_range(lp->data->t_off_to_sleep, + lp->data->t_off_to_sleep + 10); + lp->sleep = true; + } +} + +static inline void +at86rf230_awake(struct at86rf230_local *lp) +{ + if (gpio_is_valid(lp->slp_tr)) { + gpio_set_value(lp->slp_tr, 0); + usleep_range(lp->data->t_sleep_to_off, + lp->data->t_sleep_to_off + 100); + lp->sleep = false; + } +} + static inline int __at86rf230_write(struct at86rf230_local *lp, unsigned int addr, unsigned int data) { - return regmap_write(lp->regmap, addr, data); + bool sleep = lp->sleep; + int ret; + + /* awake for register setting if sleep */ + if (sleep) + at86rf230_awake(lp); + + ret = regmap_write(lp->regmap, addr, data); + + /* sleep again if was sleeping */ + if (sleep) + at86rf230_sleep(lp); + + return ret; } static inline int __at86rf230_read(struct at86rf230_local *lp, unsigned int addr, unsigned int *data) { - return regmap_read(lp->regmap, addr, data); + bool sleep = lp->sleep; + int ret; + + /* awake for register setting if sleep */ + if (sleep) + at86rf230_awake(lp); + + ret = regmap_read(lp->regmap, addr, data); + + /* sleep again if was sleeping */ + if (sleep) + at86rf230_sleep(lp); + + return ret; } static inline int @@ -147,7 +196,20 @@ at86rf230_write_subreg(struct at86rf230_local *lp, unsigned int addr, unsigned int mask, unsigned int shift, unsigned int data) { - return regmap_update_bits(lp->regmap, addr, mask, data << shift); + bool sleep = lp->sleep; + int ret; + + /* awake for register setting if sleep */ + if (sleep) + at86rf230_awake(lp); + + ret = regmap_update_bits(lp->regmap, addr, mask, data << shift); + + /* sleep again if was sleeping */ + if (sleep) + at86rf230_sleep(lp); + + return ret; } static inline void @@ -873,12 +935,7 @@ at86rf230_start(struct ieee802154_hw *hw) { struct at86rf230_local *lp = hw->priv; - if (gpio_is_valid(lp->slp_tr)) { - gpio_set_value(lp->slp_tr, 0); - usleep_range(lp->data->t_sleep_to_off, - lp->data->t_sleep_to_off + 100); - } - + at86rf230_awake(lp); enable_irq(lp->spi->irq); return at86rf230_sync_state_change(hw->priv, STATE_RX_AACK_ON); @@ -892,12 +949,7 @@ at86rf230_stop(struct ieee802154_hw *hw) at86rf230_sync_state_change(hw->priv, STATE_FORCE_TRX_OFF); disable_irq(lp->spi->irq); - - if (gpio_is_valid(lp->slp_tr)) { - gpio_set_value(lp->slp_tr, 1); - usleep_range(lp->data->t_off_to_sleep, - lp->data->t_off_to_sleep + 10); - } + at86rf230_sleep(lp); } static int @@ -1672,11 +1724,7 @@ static int at86rf230_probe(struct spi_device *spi) disable_irq(spi->irq); /* going into sleep by default */ - if (gpio_is_valid(slp_tr)) { - gpio_set_value(slp_tr, 1); - usleep_range(lp->data->t_off_to_sleep, - lp->data->t_off_to_sleep + 10); - } + at86rf230_sleep(lp); rc = ieee802154_register_hw(lp->hw); if (rc) -- cgit v1.2.3 From 74ed9d98456a7a85c9e041cd17350b8583659adf Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 16 Jun 2015 11:07:43 +0200 Subject: at86rf230: add recommended csma backoffs settings This patch adds support for a new random csma backoffs settings when going into sleep state. This is recommended according at86rf2xx datasheets. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index b839bbd4ff69..7e30a45718c9 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -945,10 +945,21 @@ static void at86rf230_stop(struct ieee802154_hw *hw) { struct at86rf230_local *lp = hw->priv; + u8 csma_seed[2]; at86rf230_sync_state_change(hw->priv, STATE_FORCE_TRX_OFF); disable_irq(lp->spi->irq); + + /* It's recommended to set random new csma_seeds before sleep state. + * Makes only sense in the stop callback, not doing this inside of + * at86rf230_sleep, this is also used when we don't transmit afterwards + * when calling start callback again. + */ + get_random_bytes(csma_seed, ARRAY_SIZE(csma_seed)); + at86rf230_write_subreg(lp, SR_CSMA_SEED_0, csma_seed[0]); + at86rf230_write_subreg(lp, SR_CSMA_SEED_1, csma_seed[1]); + at86rf230_sleep(lp); } -- cgit v1.2.3 From 30811fa663d7efa65ccec290b47a1f564485fcdd Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 16 Jun 2015 11:07:44 +0200 Subject: at86rf230: cleanup start and stop callbacks This code cleanups the start and stop callbacks by removing hw->priv and using the already dereferenced variable lp which is the same. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 7e30a45718c9..f7bd9f3ddaac 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -938,7 +938,7 @@ at86rf230_start(struct ieee802154_hw *hw) at86rf230_awake(lp); enable_irq(lp->spi->irq); - return at86rf230_sync_state_change(hw->priv, STATE_RX_AACK_ON); + return at86rf230_sync_state_change(lp, STATE_RX_AACK_ON); } static void @@ -947,7 +947,7 @@ at86rf230_stop(struct ieee802154_hw *hw) struct at86rf230_local *lp = hw->priv; u8 csma_seed[2]; - at86rf230_sync_state_change(hw->priv, STATE_FORCE_TRX_OFF); + at86rf230_sync_state_change(lp, STATE_FORCE_TRX_OFF); disable_irq(lp->spi->irq); -- cgit v1.2.3