aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-02-17 16:43:17 -0500
committerDavid S. Miller <davem@davemloft.net>2014-02-17 16:43:17 -0500
commite035b8addc544c2b4de2f8b0326ba7939abd9541 (patch)
tree08f9ec4803fd76adaf85dae04aea3a8a77188d5a
parent92e8c831d831ff97913b71e178d184106c0dee0f (diff)
parentf2fdd67c6bc89de0100410efb37de69b1c98ac03 (diff)
Merge branch 'ieee802154'
Phoebe Buckheister says: ==================== ieee802154: support rf212 and extended mac features this patch set adds support for the RF212 radio chip to the existing at86rf230 driver and adds support for numerous features of the RF212 chips to the ieee802154 stack. These features include CSMA parameter configuration, transmit power control, CCA parameter configuration, and automatic retransmission of frames. Netlink APIs are provided for all new options introduced in this set. Many features might also work for RF230, but since I have no such chips at my disposal, most new features are implemented only for RF212. Changes since v2: * Indentation Changes since v1: * CodingStyle compliance. Thanks Sergei Shtylyov * Add CSMA parameters to netlink phy list that were forgotten in v1 ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ieee802154/at86rf230.c433
-rw-r--r--include/linux/nl802154.h12
-rw-r--r--include/net/mac802154.h35
-rw-r--r--include/net/wpan-phy.h19
-rw-r--r--net/ieee802154/ieee802154.h1
-rw-r--r--net/ieee802154/netlink.c1
-rw-r--r--net/ieee802154/nl-phy.c198
-rw-r--r--net/ieee802154/nl_policy.c10
-rw-r--r--net/ieee802154/wpan-class.c10
-rw-r--r--net/mac802154/ieee802154_dev.c67
10 files changed, 668 insertions, 118 deletions
diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c
index ab31544bc254..34bf011584fb 100644
--- a/drivers/net/ieee802154/at86rf230.c
+++ b/drivers/net/ieee802154/at86rf230.c
@@ -37,7 +37,6 @@
37 37
38struct at86rf230_local { 38struct at86rf230_local {
39 struct spi_device *spi; 39 struct spi_device *spi;
40 int rstn, slp_tr, dig2;
41 40
42 u8 part; 41 u8 part;
43 u8 vers; 42 u8 vers;
@@ -53,8 +52,16 @@ struct at86rf230_local {
53 spinlock_t lock; 52 spinlock_t lock;
54 bool irq_busy; 53 bool irq_busy;
55 bool is_tx; 54 bool is_tx;
55 bool tx_aret;
56
57 int rssi_base_val;
56}; 58};
57 59
60static inline int is_rf212(struct at86rf230_local *local)
61{
62 return local->part == 7;
63}
64
58#define RG_TRX_STATUS (0x01) 65#define RG_TRX_STATUS (0x01)
59#define SR_TRX_STATUS 0x01, 0x1f, 0 66#define SR_TRX_STATUS 0x01, 0x1f, 0
60#define SR_RESERVED_01_3 0x01, 0x20, 5 67#define SR_RESERVED_01_3 0x01, 0x20, 5
@@ -100,7 +107,10 @@ struct at86rf230_local {
100#define SR_SFD_VALUE 0x0b, 0xff, 0 107#define SR_SFD_VALUE 0x0b, 0xff, 0
101#define RG_TRX_CTRL_2 (0x0c) 108#define RG_TRX_CTRL_2 (0x0c)
102#define SR_OQPSK_DATA_RATE 0x0c, 0x03, 0 109#define SR_OQPSK_DATA_RATE 0x0c, 0x03, 0
103#define SR_RESERVED_0c_2 0x0c, 0x7c, 2 110#define SR_SUB_MODE 0x0c, 0x04, 2
111#define SR_BPSK_QPSK 0x0c, 0x08, 3
112#define SR_OQPSK_SUB1_RC_EN 0x0c, 0x10, 4
113#define SR_RESERVED_0c_5 0x0c, 0x60, 5
104#define SR_RX_SAFE_MODE 0x0c, 0x80, 7 114#define SR_RX_SAFE_MODE 0x0c, 0x80, 7
105#define RG_ANT_DIV (0x0d) 115#define RG_ANT_DIV (0x0d)
106#define SR_ANT_CTRL 0x0d, 0x03, 0 116#define SR_ANT_CTRL 0x0d, 0x03, 0
@@ -145,7 +155,7 @@ struct at86rf230_local {
145#define SR_RESERVED_17_5 0x17, 0x08, 3 155#define SR_RESERVED_17_5 0x17, 0x08, 3
146#define SR_AACK_UPLD_RES_FT 0x17, 0x10, 4 156#define SR_AACK_UPLD_RES_FT 0x17, 0x10, 4
147#define SR_AACK_FLTR_RES_FT 0x17, 0x20, 5 157#define SR_AACK_FLTR_RES_FT 0x17, 0x20, 5
148#define SR_RESERVED_17_2 0x17, 0x40, 6 158#define SR_CSMA_LBT_MODE 0x17, 0x40, 6
149#define SR_RESERVED_17_1 0x17, 0x80, 7 159#define SR_RESERVED_17_1 0x17, 0x80, 7
150#define RG_FTN_CTRL (0x18) 160#define RG_FTN_CTRL (0x18)
151#define SR_RESERVED_18_2 0x18, 0x7f, 0 161#define SR_RESERVED_18_2 0x18, 0x7f, 0
@@ -244,6 +254,57 @@ struct at86rf230_local {
244#define STATE_TRANSITION_IN_PROGRESS 0x1F 254#define STATE_TRANSITION_IN_PROGRESS 0x1F
245 255
246static int 256static int
257__at86rf230_detect_device(struct spi_device *spi, u16 *man_id, u8 *part,
258 u8 *version)
259{
260 u8 data[4];
261 u8 *buf = kmalloc(2, GFP_KERNEL);
262 int status;
263 struct spi_message msg;
264 struct spi_transfer xfer = {
265 .len = 2,
266 .tx_buf = buf,
267 .rx_buf = buf,
268 };
269 u8 reg;
270
271 if (!buf)
272 return -ENOMEM;
273
274 for (reg = RG_PART_NUM; reg <= RG_MAN_ID_1; reg++) {
275 buf[0] = (reg & CMD_REG_MASK) | CMD_REG;
276 buf[1] = 0xff;
277 dev_vdbg(&spi->dev, "buf[0] = %02x\n", buf[0]);
278 spi_message_init(&msg);
279 spi_message_add_tail(&xfer, &msg);
280
281 status = spi_sync(spi, &msg);
282 dev_vdbg(&spi->dev, "status = %d\n", status);
283 if (msg.status)
284 status = msg.status;
285
286 dev_vdbg(&spi->dev, "status = %d\n", status);
287 dev_vdbg(&spi->dev, "buf[0] = %02x\n", buf[0]);
288 dev_vdbg(&spi->dev, "buf[1] = %02x\n", buf[1]);
289
290 if (status == 0)
291 data[reg - RG_PART_NUM] = buf[1];
292 else
293 break;
294 }
295
296 if (status == 0) {
297 *part = data[0];
298 *version = data[1];
299 *man_id = (data[3] << 8) | data[2];
300 }
301
302 kfree(buf);
303
304 return status;
305}
306
307static int
247__at86rf230_write(struct at86rf230_local *lp, u8 addr, u8 data) 308__at86rf230_write(struct at86rf230_local *lp, u8 addr, u8 data)
248{ 309{
249 u8 *buf = lp->buf; 310 u8 *buf = lp->buf;
@@ -489,7 +550,9 @@ at86rf230_state(struct ieee802154_dev *dev, int state)
489 } while (val == STATE_TRANSITION_IN_PROGRESS); 550 } while (val == STATE_TRANSITION_IN_PROGRESS);
490 551
491 552
492 if (val == desired_status) 553 if (val == desired_status ||
554 (desired_status == STATE_RX_ON && val == STATE_BUSY_RX) ||
555 (desired_status == STATE_RX_AACK_ON && val == STATE_BUSY_RX_AACK))
493 return 0; 556 return 0;
494 557
495 pr_err("unexpected state change: %d, asked for %d\n", val, state); 558 pr_err("unexpected state change: %d, asked for %d\n", val, state);
@@ -510,7 +573,11 @@ at86rf230_start(struct ieee802154_dev *dev)
510 if (rc) 573 if (rc)
511 return rc; 574 return rc;
512 575
513 return at86rf230_state(dev, STATE_RX_ON); 576 rc = at86rf230_state(dev, STATE_FORCE_TX_ON);
577 if (rc)
578 return rc;
579
580 return at86rf230_state(dev, STATE_RX_AACK_ON);
514} 581}
515 582
516static void 583static void
@@ -520,6 +587,39 @@ at86rf230_stop(struct ieee802154_dev *dev)
520} 587}
521 588
522static int 589static int
590at86rf230_set_channel(struct at86rf230_local *lp, int page, int channel)
591{
592 lp->rssi_base_val = -91;
593
594 return at86rf230_write_subreg(lp, SR_CHANNEL, channel);
595}
596
597static int
598at86rf212_set_channel(struct at86rf230_local *lp, int page, int channel)
599{
600 int rc;
601
602 if (channel == 0)
603 rc = at86rf230_write_subreg(lp, SR_SUB_MODE, 0);
604 else
605 rc = at86rf230_write_subreg(lp, SR_SUB_MODE, 1);
606 if (rc < 0)
607 return rc;
608
609 if (page == 0) {
610 rc = at86rf230_write_subreg(lp, SR_BPSK_QPSK, 0);
611 lp->rssi_base_val = -100;
612 } else {
613 rc = at86rf230_write_subreg(lp, SR_BPSK_QPSK, 1);
614 lp->rssi_base_val = -98;
615 }
616 if (rc < 0)
617 return rc;
618
619 return at86rf230_write_subreg(lp, SR_CHANNEL, channel);
620}
621
622static int
523at86rf230_channel(struct ieee802154_dev *dev, int page, int channel) 623at86rf230_channel(struct ieee802154_dev *dev, int page, int channel)
524{ 624{
525 struct at86rf230_local *lp = dev->priv; 625 struct at86rf230_local *lp = dev->priv;
@@ -527,14 +627,22 @@ at86rf230_channel(struct ieee802154_dev *dev, int page, int channel)
527 627
528 might_sleep(); 628 might_sleep();
529 629
530 if (page != 0 || channel < 11 || channel > 26) { 630 if (page < 0 || page > 31 ||
631 !(lp->dev->phy->channels_supported[page] & BIT(channel))) {
531 WARN_ON(1); 632 WARN_ON(1);
532 return -EINVAL; 633 return -EINVAL;
533 } 634 }
534 635
535 rc = at86rf230_write_subreg(lp, SR_CHANNEL, channel); 636 if (is_rf212(lp))
637 rc = at86rf212_set_channel(lp, page, channel);
638 else
639 rc = at86rf230_set_channel(lp, page, channel);
640 if (rc < 0)
641 return rc;
642
536 msleep(1); /* Wait for PLL */ 643 msleep(1); /* Wait for PLL */
537 dev->phy->current_channel = channel; 644 dev->phy->current_channel = channel;
645 dev->phy->current_page = page;
538 646
539 return 0; 647 return 0;
540} 648}
@@ -568,6 +676,12 @@ at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
568 if (rc) 676 if (rc)
569 goto err_rx; 677 goto err_rx;
570 678
679 if (lp->tx_aret) {
680 rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TX_ARET_ON);
681 if (rc)
682 goto err_rx;
683 }
684
571 rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_BUSY_TX); 685 rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_BUSY_TX);
572 if (rc) 686 if (rc)
573 goto err_rx; 687 goto err_rx;
@@ -668,6 +782,98 @@ at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev,
668 return 0; 782 return 0;
669} 783}
670 784
785static int
786at86rf212_set_txpower(struct ieee802154_dev *dev, int db)
787{
788 struct at86rf230_local *lp = dev->priv;
789 int rc;
790
791 /* typical maximum output is 5dBm with RG_PHY_TX_PWR 0x60, lower five
792 * bits decrease power in 1dB steps. 0x60 represents extra PA gain of
793 * 0dB.
794 * thus, supported values for db range from -26 to 5, for 31dB of
795 * reduction to 0dB of reduction.
796 */
797 if (db > 5 || db < -26)
798 return -EINVAL;
799
800 db = -(db - 5);
801
802 rc = __at86rf230_write(lp, RG_PHY_TX_PWR, 0x60 | db);
803 if (rc)
804 return rc;
805
806 return 0;
807}
808
809static int
810at86rf212_set_lbt(struct ieee802154_dev *dev, bool on)
811{
812 struct at86rf230_local *lp = dev->priv;
813
814 return at86rf230_write_subreg(lp, SR_CSMA_LBT_MODE, on);
815}
816
817static int
818at86rf212_set_cca_mode(struct ieee802154_dev *dev, u8 mode)
819{
820 struct at86rf230_local *lp = dev->priv;
821
822 return at86rf230_write_subreg(lp, SR_CCA_MODE, mode);
823}
824
825static int
826at86rf212_set_cca_ed_level(struct ieee802154_dev *dev, s32 level)
827{
828 struct at86rf230_local *lp = dev->priv;
829 int desens_steps;
830
831 if (level < lp->rssi_base_val || level > 30)
832 return -EINVAL;
833
834 desens_steps = (level - lp->rssi_base_val) * 100 / 207;
835
836 return at86rf230_write_subreg(lp, SR_CCA_ED_THRES, desens_steps);
837}
838
839static int
840at86rf212_set_csma_params(struct ieee802154_dev *dev, u8 min_be, u8 max_be,
841 u8 retries)
842{
843 struct at86rf230_local *lp = dev->priv;
844 int rc;
845
846 if (min_be > max_be || max_be > 8 || retries > 5)
847 return -EINVAL;
848
849 rc = at86rf230_write_subreg(lp, SR_MIN_BE, min_be);
850 if (rc)
851 return rc;
852
853 rc = at86rf230_write_subreg(lp, SR_MAX_BE, max_be);
854 if (rc)
855 return rc;
856
857 return at86rf230_write_subreg(lp, SR_MAX_CSMA_RETRIES, max_be);
858}
859
860static int
861at86rf212_set_frame_retries(struct ieee802154_dev *dev, s8 retries)
862{
863 struct at86rf230_local *lp = dev->priv;
864 int rc = 0;
865
866 if (retries < -1 || retries > 15)
867 return -EINVAL;
868
869 lp->tx_aret = retries >= 0;
870
871 if (retries >= 0)
872 rc = at86rf230_write_subreg(lp, SR_MAX_FRAME_RETRIES, retries);
873
874 return rc;
875}
876
671static struct ieee802154_ops at86rf230_ops = { 877static struct ieee802154_ops at86rf230_ops = {
672 .owner = THIS_MODULE, 878 .owner = THIS_MODULE,
673 .xmit = at86rf230_xmit, 879 .xmit = at86rf230_xmit,
@@ -678,6 +884,22 @@ static struct ieee802154_ops at86rf230_ops = {
678 .set_hw_addr_filt = at86rf230_set_hw_addr_filt, 884 .set_hw_addr_filt = at86rf230_set_hw_addr_filt,
679}; 885};
680 886
887static struct ieee802154_ops at86rf212_ops = {
888 .owner = THIS_MODULE,
889 .xmit = at86rf230_xmit,
890 .ed = at86rf230_ed,
891 .set_channel = at86rf230_channel,
892 .start = at86rf230_start,
893 .stop = at86rf230_stop,
894 .set_hw_addr_filt = at86rf230_set_hw_addr_filt,
895 .set_txpower = at86rf212_set_txpower,
896 .set_lbt = at86rf212_set_lbt,
897 .set_cca_mode = at86rf212_set_cca_mode,
898 .set_cca_ed_level = at86rf212_set_cca_ed_level,
899 .set_csma_params = at86rf212_set_csma_params,
900 .set_frame_retries = at86rf212_set_frame_retries,
901};
902
681static void at86rf230_irqwork(struct work_struct *work) 903static void at86rf230_irqwork(struct work_struct *work)
682{ 904{
683 struct at86rf230_local *lp = 905 struct at86rf230_local *lp =
@@ -752,22 +974,15 @@ static int at86rf230_hw_init(struct at86rf230_local *lp)
752 struct at86rf230_platform_data *pdata = lp->spi->dev.platform_data; 974 struct at86rf230_platform_data *pdata = lp->spi->dev.platform_data;
753 int rc, irq_pol; 975 int rc, irq_pol;
754 u8 status; 976 u8 status;
977 u8 csma_seed[2];
755 978
756 rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status); 979 rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
757 if (rc) 980 if (rc)
758 return rc; 981 return rc;
759 982
760 dev_info(&lp->spi->dev, "Status: %02x\n", status); 983 rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_FORCE_TRX_OFF);
761 if (status == STATE_P_ON) { 984 if (rc)
762 rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TRX_OFF); 985 return rc;
763 if (rc)
764 return rc;
765 msleep(1);
766 rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
767 if (rc)
768 return rc;
769 dev_info(&lp->spi->dev, "Status: %02x\n", status);
770 }
771 986
772 /* configure irq polarity, defaults to high active */ 987 /* configure irq polarity, defaults to high active */
773 if (pdata->irq_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW)) 988 if (pdata->irq_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW))
@@ -783,6 +998,14 @@ static int at86rf230_hw_init(struct at86rf230_local *lp)
783 if (rc) 998 if (rc)
784 return rc; 999 return rc;
785 1000
1001 get_random_bytes(csma_seed, ARRAY_SIZE(csma_seed));
1002 rc = at86rf230_write_subreg(lp, SR_CSMA_SEED_0, csma_seed[0]);
1003 if (rc)
1004 return rc;
1005 rc = at86rf230_write_subreg(lp, SR_CSMA_SEED_1, csma_seed[1]);
1006 if (rc)
1007 return rc;
1008
786 /* CLKM changes are applied immediately */ 1009 /* CLKM changes are applied immediately */
787 rc = at86rf230_write_subreg(lp, SR_CLKM_SHA_SEL, 0x00); 1010 rc = at86rf230_write_subreg(lp, SR_CLKM_SHA_SEL, 0x00);
788 if (rc) 1011 if (rc)
@@ -795,16 +1018,6 @@ static int at86rf230_hw_init(struct at86rf230_local *lp)
795 /* Wait the next SLEEP cycle */ 1018 /* Wait the next SLEEP cycle */
796 msleep(100); 1019 msleep(100);
797 1020
798 rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TX_ON);
799 if (rc)
800 return rc;
801 msleep(1);
802
803 rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
804 if (rc)
805 return rc;
806 dev_info(&lp->spi->dev, "Status: %02x\n", status);
807
808 rc = at86rf230_read_subreg(lp, SR_DVDD_OK, &status); 1021 rc = at86rf230_read_subreg(lp, SR_DVDD_OK, &status);
809 if (rc) 1022 if (rc)
810 return rc; 1023 return rc;
@@ -824,26 +1037,18 @@ static int at86rf230_hw_init(struct at86rf230_local *lp)
824 return 0; 1037 return 0;
825} 1038}
826 1039
827static void at86rf230_fill_data(struct spi_device *spi)
828{
829 struct at86rf230_local *lp = spi_get_drvdata(spi);
830 struct at86rf230_platform_data *pdata = spi->dev.platform_data;
831
832 lp->rstn = pdata->rstn;
833 lp->slp_tr = pdata->slp_tr;
834 lp->dig2 = pdata->dig2;
835}
836
837static int at86rf230_probe(struct spi_device *spi) 1040static int at86rf230_probe(struct spi_device *spi)
838{ 1041{
839 struct at86rf230_platform_data *pdata; 1042 struct at86rf230_platform_data *pdata;
840 struct ieee802154_dev *dev; 1043 struct ieee802154_dev *dev;
841 struct at86rf230_local *lp; 1044 struct at86rf230_local *lp;
842 u8 man_id_0, man_id_1, status; 1045 u16 man_id = 0;
1046 u8 part = 0, version = 0, status;
843 irq_handler_t irq_handler; 1047 irq_handler_t irq_handler;
844 work_func_t irq_worker; 1048 work_func_t irq_worker;
845 int rc, supported = 0; 1049 int rc;
846 const char *chip; 1050 const char *chip;
1051 struct ieee802154_ops *ops = NULL;
847 1052
848 if (!spi->irq) { 1053 if (!spi->irq) {
849 dev_err(&spi->dev, "no IRQ specified\n"); 1054 dev_err(&spi->dev, "no IRQ specified\n");
@@ -856,116 +1061,117 @@ static int at86rf230_probe(struct spi_device *spi)
856 return -EINVAL; 1061 return -EINVAL;
857 } 1062 }
858 1063
859 dev = ieee802154_alloc_device(sizeof(*lp), &at86rf230_ops); 1064 rc = gpio_request(pdata->rstn, "rstn");
860 if (!dev)
861 return -ENOMEM;
862
863 lp = dev->priv;
864 lp->dev = dev;
865
866 lp->spi = spi;
867
868 dev->parent = &spi->dev;
869 dev->extra_tx_headroom = 0;
870 /* We do support only 2.4 Ghz */
871 dev->phy->channels_supported[0] = 0x7FFF800;
872 dev->flags = IEEE802154_HW_OMIT_CKSUM;
873
874 if (pdata->irq_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
875 irq_worker = at86rf230_irqwork;
876 irq_handler = at86rf230_isr;
877 } else {
878 irq_worker = at86rf230_irqwork_level;
879 irq_handler = at86rf230_isr_level;
880 }
881
882 mutex_init(&lp->bmux);
883 INIT_WORK(&lp->irqwork, irq_worker);
884 spin_lock_init(&lp->lock);
885 init_completion(&lp->tx_complete);
886
887 spi_set_drvdata(spi, lp);
888
889 at86rf230_fill_data(spi);
890
891 rc = gpio_request(lp->rstn, "rstn");
892 if (rc) 1065 if (rc)
893 goto err_rstn; 1066 return rc;
894 1067
895 if (gpio_is_valid(lp->slp_tr)) { 1068 if (gpio_is_valid(pdata->slp_tr)) {
896 rc = gpio_request(lp->slp_tr, "slp_tr"); 1069 rc = gpio_request(pdata->slp_tr, "slp_tr");
897 if (rc) 1070 if (rc)
898 goto err_slp_tr; 1071 goto err_slp_tr;
899 } 1072 }
900 1073
901 rc = gpio_direction_output(lp->rstn, 1); 1074 rc = gpio_direction_output(pdata->rstn, 1);
902 if (rc) 1075 if (rc)
903 goto err_gpio_dir; 1076 goto err_gpio_dir;
904 1077
905 if (gpio_is_valid(lp->slp_tr)) { 1078 if (gpio_is_valid(pdata->slp_tr)) {
906 rc = gpio_direction_output(lp->slp_tr, 0); 1079 rc = gpio_direction_output(pdata->slp_tr, 0);
907 if (rc) 1080 if (rc)
908 goto err_gpio_dir; 1081 goto err_gpio_dir;
909 } 1082 }
910 1083
911 /* Reset */ 1084 /* Reset */
912 msleep(1); 1085 msleep(1);
913 gpio_set_value(lp->rstn, 0); 1086 gpio_set_value(pdata->rstn, 0);
914 msleep(1); 1087 msleep(1);
915 gpio_set_value(lp->rstn, 1); 1088 gpio_set_value(pdata->rstn, 1);
916 msleep(1); 1089 msleep(1);
917 1090
918 rc = at86rf230_read_subreg(lp, SR_MAN_ID_0, &man_id_0); 1091 rc = __at86rf230_detect_device(spi, &man_id, &part, &version);
919 if (rc) 1092 if (rc < 0)
920 goto err_gpio_dir;
921 rc = at86rf230_read_subreg(lp, SR_MAN_ID_1, &man_id_1);
922 if (rc)
923 goto err_gpio_dir; 1093 goto err_gpio_dir;
924 1094
925 if (man_id_1 != 0x00 || man_id_0 != 0x1f) { 1095 if (man_id != 0x001f) {
926 dev_err(&spi->dev, "Non-Atmel dev found (MAN_ID %02x %02x)\n", 1096 dev_err(&spi->dev, "Non-Atmel dev found (MAN_ID %02x %02x)\n",
927 man_id_1, man_id_0); 1097 man_id >> 8, man_id & 0xFF);
928 rc = -EINVAL; 1098 rc = -EINVAL;
929 goto err_gpio_dir; 1099 goto err_gpio_dir;
930 } 1100 }
931 1101
932 rc = at86rf230_read_subreg(lp, SR_PART_NUM, &lp->part); 1102 switch (part) {
933 if (rc)
934 goto err_gpio_dir;
935
936 rc = at86rf230_read_subreg(lp, SR_VERSION_NUM, &lp->vers);
937 if (rc)
938 goto err_gpio_dir;
939
940 switch (lp->part) {
941 case 2: 1103 case 2:
942 chip = "at86rf230"; 1104 chip = "at86rf230";
943 /* supported = 1; FIXME: should be easy to support; */ 1105 /* FIXME: should be easy to support; */
944 break; 1106 break;
945 case 3: 1107 case 3:
946 chip = "at86rf231"; 1108 chip = "at86rf231";
947 supported = 1; 1109 ops = &at86rf230_ops;
1110 break;
1111 case 7:
1112 chip = "at86rf212";
1113 if (version == 1)
1114 ops = &at86rf212_ops;
948 break; 1115 break;
949 default: 1116 default:
950 chip = "UNKNOWN"; 1117 chip = "UNKNOWN";
951 break; 1118 break;
952 } 1119 }
953 1120
954 dev_info(&spi->dev, "Detected %s chip version %d\n", chip, lp->vers); 1121 dev_info(&spi->dev, "Detected %s chip version %d\n", chip, version);
955 if (!supported) { 1122 if (!ops) {
956 rc = -ENOTSUPP; 1123 rc = -ENOTSUPP;
957 goto err_gpio_dir; 1124 goto err_gpio_dir;
958 } 1125 }
959 1126
1127 dev = ieee802154_alloc_device(sizeof(*lp), ops);
1128 if (!dev) {
1129 rc = -ENOMEM;
1130 goto err_gpio_dir;
1131 }
1132
1133 lp = dev->priv;
1134 lp->dev = dev;
1135 lp->part = part;
1136 lp->vers = version;
1137
1138 lp->spi = spi;
1139
1140 dev->parent = &spi->dev;
1141 dev->extra_tx_headroom = 0;
1142 dev->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK;
1143
1144 if (pdata->irq_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
1145 irq_worker = at86rf230_irqwork;
1146 irq_handler = at86rf230_isr;
1147 } else {
1148 irq_worker = at86rf230_irqwork_level;
1149 irq_handler = at86rf230_isr_level;
1150 }
1151
1152 mutex_init(&lp->bmux);
1153 INIT_WORK(&lp->irqwork, irq_worker);
1154 spin_lock_init(&lp->lock);
1155 init_completion(&lp->tx_complete);
1156
1157 spi_set_drvdata(spi, lp);
1158
1159 if (is_rf212(lp)) {
1160 dev->phy->channels_supported[0] = 0x00007FF;
1161 dev->phy->channels_supported[2] = 0x00007FF;
1162 } else {
1163 dev->phy->channels_supported[0] = 0x7FFF800;
1164 }
1165
960 rc = at86rf230_hw_init(lp); 1166 rc = at86rf230_hw_init(lp);
961 if (rc) 1167 if (rc)
962 goto err_gpio_dir; 1168 goto err_hw_init;
963 1169
964 rc = request_irq(spi->irq, irq_handler, 1170 rc = request_irq(spi->irq, irq_handler,
965 IRQF_SHARED | pdata->irq_type, 1171 IRQF_SHARED | pdata->irq_type,
966 dev_name(&spi->dev), lp); 1172 dev_name(&spi->dev), lp);
967 if (rc) 1173 if (rc)
968 goto err_gpio_dir; 1174 goto err_hw_init;
969 1175
970 /* Read irq status register to reset irq line */ 1176 /* Read irq status register to reset irq line */
971 rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &status); 1177 rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &status);
@@ -980,30 +1186,33 @@ static int at86rf230_probe(struct spi_device *spi)
980 1186
981err_irq: 1187err_irq:
982 free_irq(spi->irq, lp); 1188 free_irq(spi->irq, lp);
1189err_hw_init:
983 flush_work(&lp->irqwork); 1190 flush_work(&lp->irqwork);
984err_gpio_dir: 1191 spi_set_drvdata(spi, NULL);
985 if (gpio_is_valid(lp->slp_tr))
986 gpio_free(lp->slp_tr);
987err_slp_tr:
988 gpio_free(lp->rstn);
989err_rstn:
990 mutex_destroy(&lp->bmux); 1192 mutex_destroy(&lp->bmux);
991 ieee802154_free_device(lp->dev); 1193 ieee802154_free_device(lp->dev);
1194
1195err_gpio_dir:
1196 if (gpio_is_valid(pdata->slp_tr))
1197 gpio_free(pdata->slp_tr);
1198err_slp_tr:
1199 gpio_free(pdata->rstn);
992 return rc; 1200 return rc;
993} 1201}
994 1202
995static int at86rf230_remove(struct spi_device *spi) 1203static int at86rf230_remove(struct spi_device *spi)
996{ 1204{
997 struct at86rf230_local *lp = spi_get_drvdata(spi); 1205 struct at86rf230_local *lp = spi_get_drvdata(spi);
1206 struct at86rf230_platform_data *pdata = spi->dev.platform_data;
998 1207
999 ieee802154_unregister_device(lp->dev); 1208 ieee802154_unregister_device(lp->dev);
1000 1209
1001 free_irq(spi->irq, lp); 1210 free_irq(spi->irq, lp);
1002 flush_work(&lp->irqwork); 1211 flush_work(&lp->irqwork);
1003 1212
1004 if (gpio_is_valid(lp->slp_tr)) 1213 if (gpio_is_valid(pdata->slp_tr))
1005 gpio_free(lp->slp_tr); 1214 gpio_free(pdata->slp_tr);
1006 gpio_free(lp->rstn); 1215 gpio_free(pdata->rstn);
1007 1216
1008 mutex_destroy(&lp->bmux); 1217 mutex_destroy(&lp->bmux);
1009 ieee802154_free_device(lp->dev); 1218 ieee802154_free_device(lp->dev);
diff --git a/include/linux/nl802154.h b/include/linux/nl802154.h
index fd4f2d1cdf6c..e110b8c266f5 100644
--- a/include/linux/nl802154.h
+++ b/include/linux/nl802154.h
@@ -70,6 +70,16 @@ enum {
70 IEEE802154_ATTR_PHY_NAME, 70 IEEE802154_ATTR_PHY_NAME,
71 IEEE802154_ATTR_DEV_TYPE, 71 IEEE802154_ATTR_DEV_TYPE,
72 72
73 IEEE802154_ATTR_TXPOWER,
74 IEEE802154_ATTR_LBT_ENABLED,
75 IEEE802154_ATTR_CCA_MODE,
76 IEEE802154_ATTR_CCA_ED_LEVEL,
77 IEEE802154_ATTR_CSMA_RETRIES,
78 IEEE802154_ATTR_CSMA_MIN_BE,
79 IEEE802154_ATTR_CSMA_MAX_BE,
80
81 IEEE802154_ATTR_FRAME_RETRIES,
82
73 __IEEE802154_ATTR_MAX, 83 __IEEE802154_ATTR_MAX,
74}; 84};
75 85
@@ -122,6 +132,8 @@ enum {
122 IEEE802154_ADD_IFACE, 132 IEEE802154_ADD_IFACE,
123 IEEE802154_DEL_IFACE, 133 IEEE802154_DEL_IFACE,
124 134
135 IEEE802154_SET_PHYPARAMS,
136
125 __IEEE802154_CMD_MAX, 137 __IEEE802154_CMD_MAX,
126}; 138};
127 139
diff --git a/include/net/mac802154.h b/include/net/mac802154.h
index 807d6b7a943f..8ca3d04e7558 100644
--- a/include/net/mac802154.h
+++ b/include/net/mac802154.h
@@ -113,6 +113,32 @@ struct ieee802154_dev {
113 * Set radio for listening on specific address. 113 * Set radio for listening on specific address.
114 * Set the device for listening on specified address. 114 * Set the device for listening on specified address.
115 * Returns either zero, or negative errno. 115 * Returns either zero, or negative errno.
116 *
117 * set_txpower:
118 * Set radio transmit power in dB. Called with pib_lock held.
119 * Returns either zero, or negative errno.
120 *
121 * set_lbt
122 * Enables or disables listen before talk on the device. Called with
123 * pib_lock held.
124 * Returns either zero, or negative errno.
125 *
126 * set_cca_mode
127 * Sets the CCA mode used by the device. Called with pib_lock held.
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.
134 *
135 * set_csma_params
136 * Sets the CSMA parameter set for the PHY. Called with pib_lock held.
137 * Returns either zero, or negative errno.
138 *
139 * set_frame_retries
140 * Sets the retransmission attempt limit. Called with pib_lock held.
141 * Returns either zero, or negative errno.
116 */ 142 */
117struct ieee802154_ops { 143struct ieee802154_ops {
118 struct module *owner; 144 struct module *owner;
@@ -129,6 +155,15 @@ struct ieee802154_ops {
129 unsigned long changed); 155 unsigned long changed);
130 int (*ieee_addr)(struct ieee802154_dev *dev, 156 int (*ieee_addr)(struct ieee802154_dev *dev,
131 u8 addr[IEEE802154_ADDR_LEN]); 157 u8 addr[IEEE802154_ADDR_LEN]);
158 int (*set_txpower)(struct ieee802154_dev *dev, int db);
159 int (*set_lbt)(struct ieee802154_dev *dev, bool on);
160 int (*set_cca_mode)(struct ieee802154_dev *dev, u8 mode);
161 int (*set_cca_ed_level)(struct ieee802154_dev *dev,
162 s32 level);
163 int (*set_csma_params)(struct ieee802154_dev *dev,
164 u8 min_be, u8 max_be, u8 retries);
165 int (*set_frame_retries)(struct ieee802154_dev *dev,
166 s8 retries);
132}; 167};
133 168
134/* Basic interface to register ieee802154 device */ 169/* Basic interface to register ieee802154 device */
diff --git a/include/net/wpan-phy.h b/include/net/wpan-phy.h
index b52bda8d13b1..10ab0fc6d4f7 100644
--- a/include/net/wpan-phy.h
+++ b/include/net/wpan-phy.h
@@ -37,15 +37,22 @@ struct wpan_phy {
37 struct mutex pib_lock; 37 struct mutex pib_lock;
38 38
39 /* 39 /*
40 * This is a PIB according to 802.15.4-2006. 40 * This is a PIB according to 802.15.4-2011.
41 * We do not provide timing-related variables, as they 41 * We do not provide timing-related variables, as they
42 * aren't used outside of driver 42 * aren't used outside of driver
43 */ 43 */
44 u8 current_channel; 44 u8 current_channel;
45 u8 current_page; 45 u8 current_page;
46 u32 channels_supported[32]; 46 u32 channels_supported[32];
47 u8 transmit_power; 47 s8 transmit_power;
48 u8 cca_mode; 48 u8 cca_mode;
49 u8 min_be;
50 u8 max_be;
51 u8 csma_retries;
52 s8 frame_retries;
53
54 bool lbt;
55 s32 cca_ed_level;
49 56
50 struct device dev; 57 struct device dev;
51 int idx; 58 int idx;
@@ -54,6 +61,14 @@ struct wpan_phy {
54 const char *name, int type); 61 const char *name, int type);
55 void (*del_iface)(struct wpan_phy *phy, struct net_device *dev); 62 void (*del_iface)(struct wpan_phy *phy, struct net_device *dev);
56 63
64 int (*set_txpower)(struct wpan_phy *phy, int db);
65 int (*set_lbt)(struct wpan_phy *phy, bool on);
66 int (*set_cca_mode)(struct wpan_phy *phy, u8 cca_mode);
67 int (*set_cca_ed_level)(struct wpan_phy *phy, int level);
68 int (*set_csma_params)(struct wpan_phy *phy, u8 min_be, u8 max_be,
69 u8 retries);
70 int (*set_frame_retries)(struct wpan_phy *phy, s8 retries);
71
57 char priv[0] __attribute__((__aligned__(NETDEV_ALIGN))); 72 char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
58}; 73};
59 74
diff --git a/net/ieee802154/ieee802154.h b/net/ieee802154/ieee802154.h
index cee4425b9956..6cbc8965be91 100644
--- a/net/ieee802154/ieee802154.h
+++ b/net/ieee802154/ieee802154.h
@@ -53,6 +53,7 @@ int ieee802154_list_phy(struct sk_buff *skb, struct genl_info *info);
53int ieee802154_dump_phy(struct sk_buff *skb, struct netlink_callback *cb); 53int ieee802154_dump_phy(struct sk_buff *skb, struct netlink_callback *cb);
54int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info); 54int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info);
55int ieee802154_del_iface(struct sk_buff *skb, struct genl_info *info); 55int ieee802154_del_iface(struct sk_buff *skb, struct genl_info *info);
56int ieee802154_set_phyparams(struct sk_buff *skb, struct genl_info *info);
56 57
57enum ieee802154_mcgrp_ids { 58enum ieee802154_mcgrp_ids {
58 IEEE802154_COORD_MCGRP, 59 IEEE802154_COORD_MCGRP,
diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c
index 43f1b2bf469f..67c151bf4b91 100644
--- a/net/ieee802154/netlink.c
+++ b/net/ieee802154/netlink.c
@@ -115,6 +115,7 @@ static const struct genl_ops ieee8021154_ops[] = {
115 ieee802154_dump_phy), 115 ieee802154_dump_phy),
116 IEEE802154_OP(IEEE802154_ADD_IFACE, ieee802154_add_iface), 116 IEEE802154_OP(IEEE802154_ADD_IFACE, ieee802154_add_iface),
117 IEEE802154_OP(IEEE802154_DEL_IFACE, ieee802154_del_iface), 117 IEEE802154_OP(IEEE802154_DEL_IFACE, ieee802154_del_iface),
118 IEEE802154_OP(IEEE802154_SET_PHYPARAMS, ieee802154_set_phyparams),
118 /* see nl-mac.c */ 119 /* see nl-mac.c */
119 IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req), 120 IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req),
120 IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp), 121 IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp),
diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c
index 89b265aea151..c9dfd6f59e34 100644
--- a/net/ieee802154/nl-phy.c
+++ b/net/ieee802154/nl-phy.c
@@ -55,7 +55,15 @@ static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 portid,
55 mutex_lock(&phy->pib_lock); 55 mutex_lock(&phy->pib_lock);
56 if (nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) || 56 if (nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) ||
57 nla_put_u8(msg, IEEE802154_ATTR_PAGE, phy->current_page) || 57 nla_put_u8(msg, IEEE802154_ATTR_PAGE, phy->current_page) ||
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) ||
60 nla_put_u8(msg, IEEE802154_ATTR_LBT_ENABLED, phy->lbt) ||
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) ||
63 nla_put_u8(msg, IEEE802154_ATTR_CSMA_RETRIES, phy->csma_retries) ||
64 nla_put_u8(msg, IEEE802154_ATTR_CSMA_MIN_BE, phy->min_be) ||
65 nla_put_u8(msg, IEEE802154_ATTR_CSMA_MAX_BE, phy->max_be) ||
66 nla_put_s8(msg, IEEE802154_ATTR_FRAME_RETRIES, phy->frame_retries))
59 goto nla_put_failure; 67 goto nla_put_failure;
60 for (i = 0; i < 32; i++) { 68 for (i = 0; i < 32; i++) {
61 if (phy->channels_supported[i]) 69 if (phy->channels_supported[i])
@@ -354,3 +362,191 @@ out_dev:
354 362
355 return rc; 363 return rc;
356} 364}
365
366static int phy_set_txpower(struct wpan_phy *phy, struct genl_info *info)
367{
368 int txpower = nla_get_s8(info->attrs[IEEE802154_ATTR_TXPOWER]);
369 int rc;
370
371 rc = phy->set_txpower(phy, txpower);
372 if (rc < 0)
373 return rc;
374
375 phy->transmit_power = txpower;
376
377 return 0;
378}
379
380static int phy_set_lbt(struct wpan_phy *phy, struct genl_info *info)
381{
382 u8 on = !!nla_get_u8(info->attrs[IEEE802154_ATTR_LBT_ENABLED]);
383 int rc;
384
385 rc = phy->set_lbt(phy, on);
386 if (rc < 0)
387 return rc;
388
389 phy->lbt = on;
390
391 return 0;
392}
393
394static int phy_set_cca_mode(struct wpan_phy *phy, struct genl_info *info)
395{
396 u8 mode = nla_get_u8(info->attrs[IEEE802154_ATTR_CCA_MODE]);
397 int rc;
398
399 if (mode > 3)
400 return -EINVAL;
401
402 rc = phy->set_cca_mode(phy, mode);
403 if (rc < 0)
404 return rc;
405
406 phy->cca_mode = mode;
407
408 return 0;
409}
410
411static int phy_set_cca_ed_level(struct wpan_phy *phy, struct genl_info *info)
412{
413 s32 level = nla_get_s32(info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL]);
414 int rc;
415
416 rc = phy->set_cca_ed_level(phy, level);
417 if (rc < 0)
418 return rc;
419
420 phy->cca_ed_level = level;
421
422 return 0;
423}
424
425static int phy_set_csma_params(struct wpan_phy *phy, struct genl_info *info)
426{
427 int rc;
428 u8 min_be = phy->min_be;
429 u8 max_be = phy->max_be;
430 u8 retries = phy->csma_retries;
431
432 if (info->attrs[IEEE802154_ATTR_CSMA_RETRIES])
433 retries = nla_get_u8(info->attrs[IEEE802154_ATTR_CSMA_RETRIES]);
434 if (info->attrs[IEEE802154_ATTR_CSMA_MIN_BE])
435 min_be = nla_get_u8(info->attrs[IEEE802154_ATTR_CSMA_MIN_BE]);
436 if (info->attrs[IEEE802154_ATTR_CSMA_MAX_BE])
437 max_be = nla_get_u8(info->attrs[IEEE802154_ATTR_CSMA_MAX_BE]);
438
439 if (retries > 5 || max_be > 8 || min_be > max_be ||
440 retries < -1 || retries > 7)
441 return -EINVAL;
442
443 rc = phy->set_csma_params(phy, min_be, max_be, retries);
444 if (rc < 0)
445 return rc;
446
447 phy->min_be = min_be;
448 phy->max_be = max_be;
449 phy->csma_retries = retries;
450
451 return 0;
452}
453
454static int phy_set_frame_retries(struct wpan_phy *phy, struct genl_info *info)
455{
456 s8 retries = nla_get_s8(info->attrs[IEEE802154_ATTR_FRAME_RETRIES]);
457 int rc;
458
459 rc = phy->set_frame_retries(phy, retries);
460 if (rc < 0)
461 return rc;
462
463 phy->frame_retries = retries;
464
465 return 0;
466}
467
468int ieee802154_set_phyparams(struct sk_buff *skb, struct genl_info *info)
469{
470 struct wpan_phy *phy;
471 const char *name;
472 int rc = -ENOTSUPP;
473
474 pr_debug("%s\n", __func__);
475
476 if (!info->attrs[IEEE802154_ATTR_PHY_NAME] &&
477 !info->attrs[IEEE802154_ATTR_LBT_ENABLED] &&
478 !info->attrs[IEEE802154_ATTR_CCA_MODE] &&
479 !info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL] &&
480 !info->attrs[IEEE802154_ATTR_CSMA_RETRIES] &&
481 !info->attrs[IEEE802154_ATTR_CSMA_MIN_BE] &&
482 !info->attrs[IEEE802154_ATTR_CSMA_MAX_BE] &&
483 !info->attrs[IEEE802154_ATTR_FRAME_RETRIES])
484 return -EINVAL;
485
486 name = nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]);
487 if (name[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] != '\0')
488 return -EINVAL; /* phy name should be null-terminated */
489
490 phy = wpan_phy_find(name);
491 if (!phy)
492 return -ENODEV;
493
494 if ((!phy->set_txpower && info->attrs[IEEE802154_ATTR_TXPOWER]) ||
495 (!phy->set_lbt && info->attrs[IEEE802154_ATTR_LBT_ENABLED]) ||
496 (!phy->set_cca_mode && info->attrs[IEEE802154_ATTR_CCA_MODE]) ||
497 (!phy->set_cca_ed_level &&
498 info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL]))
499 goto out;
500
501 mutex_lock(&phy->pib_lock);
502
503 if (info->attrs[IEEE802154_ATTR_TXPOWER]) {
504 rc = phy_set_txpower(phy, info);
505 if (rc < 0)
506 goto error;
507 }
508
509 if (info->attrs[IEEE802154_ATTR_LBT_ENABLED]) {
510 rc = phy_set_lbt(phy, info);
511 if (rc < 0)
512 goto error;
513 }
514
515 if (info->attrs[IEEE802154_ATTR_CCA_MODE]) {
516 rc = phy_set_cca_mode(phy, info);
517 if (rc < 0)
518 goto error;
519 }
520
521 if (info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL]) {
522 rc = phy_set_cca_ed_level(phy, info);
523 if (rc < 0)
524 goto error;
525 }
526
527 if (info->attrs[IEEE802154_ATTR_CSMA_RETRIES] ||
528 info->attrs[IEEE802154_ATTR_CSMA_MIN_BE] ||
529 info->attrs[IEEE802154_ATTR_CSMA_MAX_BE]) {
530 rc = phy_set_csma_params(phy, info);
531 if (rc < 0)
532 goto error;
533 }
534
535 if (info->attrs[IEEE802154_ATTR_FRAME_RETRIES]) {
536 rc = phy_set_frame_retries(phy, info);
537 if (rc < 0)
538 goto error;
539 }
540
541 mutex_unlock(&phy->pib_lock);
542
543 wpan_phy_put(phy);
544
545 return 0;
546
547error:
548 mutex_unlock(&phy->pib_lock);
549out:
550 wpan_phy_put(phy);
551 return rc;
552}
diff --git a/net/ieee802154/nl_policy.c b/net/ieee802154/nl_policy.c
index 6adda4d46f95..fd7be5e45cef 100644
--- a/net/ieee802154/nl_policy.c
+++ b/net/ieee802154/nl_policy.c
@@ -52,5 +52,15 @@ const struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = {
52 [IEEE802154_ATTR_DURATION] = { .type = NLA_U8, }, 52 [IEEE802154_ATTR_DURATION] = { .type = NLA_U8, },
53 [IEEE802154_ATTR_ED_LIST] = { .len = 27 }, 53 [IEEE802154_ATTR_ED_LIST] = { .len = 27 },
54 [IEEE802154_ATTR_CHANNEL_PAGE_LIST] = { .len = 32 * 4, }, 54 [IEEE802154_ATTR_CHANNEL_PAGE_LIST] = { .len = 32 * 4, },
55
56 [IEEE802154_ATTR_TXPOWER] = { .type = NLA_S8, },
57 [IEEE802154_ATTR_LBT_ENABLED] = { .type = NLA_U8, },
58 [IEEE802154_ATTR_CCA_MODE] = { .type = NLA_U8, },
59 [IEEE802154_ATTR_CCA_ED_LEVEL] = { .type = NLA_S32, },
60 [IEEE802154_ATTR_CSMA_RETRIES] = { .type = NLA_U8, },
61 [IEEE802154_ATTR_CSMA_MIN_BE] = { .type = NLA_U8, },
62 [IEEE802154_ATTR_CSMA_MAX_BE] = { .type = NLA_U8, },
63
64 [IEEE802154_ATTR_FRAME_RETRIES] = { .type = NLA_S8, },
55}; 65};
56 66
diff --git a/net/ieee802154/wpan-class.c b/net/ieee802154/wpan-class.c
index 4dd37615a749..edd0962d55f9 100644
--- a/net/ieee802154/wpan-class.c
+++ b/net/ieee802154/wpan-class.c
@@ -44,9 +44,7 @@ static DEVICE_ATTR_RO(name);
44 44
45MASTER_SHOW(current_channel, "%d"); 45MASTER_SHOW(current_channel, "%d");
46MASTER_SHOW(current_page, "%d"); 46MASTER_SHOW(current_page, "%d");
47MASTER_SHOW_COMPLEX(transmit_power, "%d +- %d dB", 47MASTER_SHOW(transmit_power, "%d +- 1 dB");
48 ((signed char) (phy->transmit_power << 2)) >> 2,
49 (phy->transmit_power >> 6) ? (phy->transmit_power >> 6) * 3 : 1);
50MASTER_SHOW(cca_mode, "%d"); 48MASTER_SHOW(cca_mode, "%d");
51 49
52static ssize_t channels_supported_show(struct device *dev, 50static ssize_t channels_supported_show(struct device *dev,
@@ -171,6 +169,12 @@ struct wpan_phy *wpan_phy_alloc(size_t priv_size)
171 phy->current_channel = -1; /* not initialised */ 169 phy->current_channel = -1; /* not initialised */
172 phy->current_page = 0; /* for compatibility */ 170 phy->current_page = 0; /* for compatibility */
173 171
172 /* defaults per 802.15.4-2011 */
173 phy->min_be = 3;
174 phy->max_be = 5;
175 phy->csma_retries = 4;
176 phy->frame_retries = -1; /* for compatibility, actual default is 3 */
177
174 return phy; 178 return phy;
175 179
176out: 180out:
diff --git a/net/mac802154/ieee802154_dev.c b/net/mac802154/ieee802154_dev.c
index 52ae6646a411..b75bb01e5c6b 100644
--- a/net/mac802154/ieee802154_dev.c
+++ b/net/mac802154/ieee802154_dev.c
@@ -165,6 +165,67 @@ err:
165 return ERR_PTR(err); 165 return ERR_PTR(err);
166} 166}
167 167
168static int mac802154_set_txpower(struct wpan_phy *phy, int db)
169{
170 struct mac802154_priv *priv = wpan_phy_priv(phy);
171
172 if (!priv->ops->set_txpower)
173 return -ENOTSUPP;
174
175 return priv->ops->set_txpower(&priv->hw, db);
176}
177
178static int mac802154_set_lbt(struct wpan_phy *phy, bool on)
179{
180 struct mac802154_priv *priv = wpan_phy_priv(phy);
181
182 if (!priv->ops->set_lbt)
183 return -ENOTSUPP;
184
185 return priv->ops->set_lbt(&priv->hw, on);
186}
187
188static int mac802154_set_cca_mode(struct wpan_phy *phy, u8 mode)
189{
190 struct mac802154_priv *priv = wpan_phy_priv(phy);
191
192 if (!priv->ops->set_cca_mode)
193 return -ENOTSUPP;
194
195 return priv->ops->set_cca_mode(&priv->hw, mode);
196}
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
208static int mac802154_set_csma_params(struct wpan_phy *phy, u8 min_be,
209 u8 max_be, u8 retries)
210{
211 struct mac802154_priv *priv = wpan_phy_priv(phy);
212
213 if (!priv->ops->set_csma_params)
214 return -ENOTSUPP;
215
216 return priv->ops->set_csma_params(&priv->hw, min_be, max_be, retries);
217}
218
219static int mac802154_set_frame_retries(struct wpan_phy *phy, s8 retries)
220{
221 struct mac802154_priv *priv = wpan_phy_priv(phy);
222
223 if (!priv->ops->set_frame_retries)
224 return -ENOTSUPP;
225
226 return priv->ops->set_frame_retries(&priv->hw, retries);
227}
228
168struct ieee802154_dev * 229struct ieee802154_dev *
169ieee802154_alloc_device(size_t priv_data_len, struct ieee802154_ops *ops) 230ieee802154_alloc_device(size_t priv_data_len, struct ieee802154_ops *ops)
170{ 231{
@@ -242,6 +303,12 @@ int ieee802154_register_device(struct ieee802154_dev *dev)
242 303
243 priv->phy->add_iface = mac802154_add_iface; 304 priv->phy->add_iface = mac802154_add_iface;
244 priv->phy->del_iface = mac802154_del_iface; 305 priv->phy->del_iface = mac802154_del_iface;
306 priv->phy->set_txpower = mac802154_set_txpower;
307 priv->phy->set_lbt = mac802154_set_lbt;
308 priv->phy->set_cca_mode = mac802154_set_cca_mode;
309 priv->phy->set_cca_ed_level = mac802154_set_cca_ed_level;
310 priv->phy->set_csma_params = mac802154_set_csma_params;
311 priv->phy->set_frame_retries = mac802154_set_frame_retries;
245 312
246 rc = wpan_phy_register(priv->phy); 313 rc = wpan_phy_register(priv->phy);
247 if (rc < 0) 314 if (rc < 0)