diff options
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2800lib.c')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2800lib.c | 457 |
1 files changed, 374 insertions, 83 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index b66e0fd8f0fa..3bb67492d754 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c | |||
@@ -1,4 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2010 Willow Garage <http://www.willowgarage.com> | ||
2 | Copyright (C) 2010 Ivo van Doorn <IvDoorn@gmail.com> | 3 | Copyright (C) 2010 Ivo van Doorn <IvDoorn@gmail.com> |
3 | Copyright (C) 2009 Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 4 | Copyright (C) 2009 Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> |
4 | Copyright (C) 2009 Gertjan van Wingerde <gwingerde@gmail.com> | 5 | Copyright (C) 2009 Gertjan van Wingerde <gwingerde@gmail.com> |
@@ -254,6 +255,23 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, | |||
254 | } | 255 | } |
255 | EXPORT_SYMBOL_GPL(rt2800_mcu_request); | 256 | EXPORT_SYMBOL_GPL(rt2800_mcu_request); |
256 | 257 | ||
258 | int rt2800_wait_csr_ready(struct rt2x00_dev *rt2x00dev) | ||
259 | { | ||
260 | unsigned int i = 0; | ||
261 | u32 reg; | ||
262 | |||
263 | for (i = 0; i < REGISTER_BUSY_COUNT; i++) { | ||
264 | rt2800_register_read(rt2x00dev, MAC_CSR0, ®); | ||
265 | if (reg && reg != ~0) | ||
266 | return 0; | ||
267 | msleep(1); | ||
268 | } | ||
269 | |||
270 | ERROR(rt2x00dev, "Unstable hardware.\n"); | ||
271 | return -EBUSY; | ||
272 | } | ||
273 | EXPORT_SYMBOL_GPL(rt2800_wait_csr_ready); | ||
274 | |||
257 | int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev) | 275 | int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev) |
258 | { | 276 | { |
259 | unsigned int i; | 277 | unsigned int i; |
@@ -367,19 +385,16 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev, | |||
367 | u32 reg; | 385 | u32 reg; |
368 | 386 | ||
369 | /* | 387 | /* |
370 | * Wait for stable hardware. | 388 | * If driver doesn't wake up firmware here, |
389 | * rt2800_load_firmware will hang forever when interface is up again. | ||
371 | */ | 390 | */ |
372 | for (i = 0; i < REGISTER_BUSY_COUNT; i++) { | 391 | rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0x00000000); |
373 | rt2800_register_read(rt2x00dev, MAC_CSR0, ®); | ||
374 | if (reg && reg != ~0) | ||
375 | break; | ||
376 | msleep(1); | ||
377 | } | ||
378 | 392 | ||
379 | if (i == REGISTER_BUSY_COUNT) { | 393 | /* |
380 | ERROR(rt2x00dev, "Unstable hardware.\n"); | 394 | * Wait for stable hardware. |
395 | */ | ||
396 | if (rt2800_wait_csr_ready(rt2x00dev)) | ||
381 | return -EBUSY; | 397 | return -EBUSY; |
382 | } | ||
383 | 398 | ||
384 | if (rt2x00_is_pci(rt2x00dev)) | 399 | if (rt2x00_is_pci(rt2x00dev)) |
385 | rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000002); | 400 | rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000002); |
@@ -427,8 +442,10 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev, | |||
427 | } | 442 | } |
428 | EXPORT_SYMBOL_GPL(rt2800_load_firmware); | 443 | EXPORT_SYMBOL_GPL(rt2800_load_firmware); |
429 | 444 | ||
430 | void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc) | 445 | void rt2800_write_tx_data(struct queue_entry *entry, |
446 | struct txentry_desc *txdesc) | ||
431 | { | 447 | { |
448 | __le32 *txwi = rt2800_drv_get_txwi(entry); | ||
432 | u32 word; | 449 | u32 word; |
433 | 450 | ||
434 | /* | 451 | /* |
@@ -437,7 +454,8 @@ void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc) | |||
437 | rt2x00_desc_read(txwi, 0, &word); | 454 | rt2x00_desc_read(txwi, 0, &word); |
438 | rt2x00_set_field32(&word, TXWI_W0_FRAG, | 455 | rt2x00_set_field32(&word, TXWI_W0_FRAG, |
439 | test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); | 456 | test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); |
440 | rt2x00_set_field32(&word, TXWI_W0_MIMO_PS, 0); | 457 | rt2x00_set_field32(&word, TXWI_W0_MIMO_PS, |
458 | test_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags)); | ||
441 | rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0); | 459 | rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0); |
442 | rt2x00_set_field32(&word, TXWI_W0_TS, | 460 | rt2x00_set_field32(&word, TXWI_W0_TS, |
443 | test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags)); | 461 | test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags)); |
@@ -465,7 +483,7 @@ void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc) | |||
465 | txdesc->key_idx : 0xff); | 483 | txdesc->key_idx : 0xff); |
466 | rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT, | 484 | rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT, |
467 | txdesc->length); | 485 | txdesc->length); |
468 | rt2x00_set_field32(&word, TXWI_W1_PACKETID, txdesc->queue + 1); | 486 | rt2x00_set_field32(&word, TXWI_W1_PACKETID, txdesc->qid + 1); |
469 | rt2x00_desc_write(txwi, 1, word); | 487 | rt2x00_desc_write(txwi, 1, word); |
470 | 488 | ||
471 | /* | 489 | /* |
@@ -478,7 +496,7 @@ void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc) | |||
478 | _rt2x00_desc_write(txwi, 2, 0 /* skbdesc->iv[0] */); | 496 | _rt2x00_desc_write(txwi, 2, 0 /* skbdesc->iv[0] */); |
479 | _rt2x00_desc_write(txwi, 3, 0 /* skbdesc->iv[1] */); | 497 | _rt2x00_desc_write(txwi, 3, 0 /* skbdesc->iv[1] */); |
480 | } | 498 | } |
481 | EXPORT_SYMBOL_GPL(rt2800_write_txwi); | 499 | EXPORT_SYMBOL_GPL(rt2800_write_tx_data); |
482 | 500 | ||
483 | static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxwi_w2) | 501 | static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxwi_w2) |
484 | { | 502 | { |
@@ -490,7 +508,7 @@ static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxwi_w2) | |||
490 | u8 offset1; | 508 | u8 offset1; |
491 | u8 offset2; | 509 | u8 offset2; |
492 | 510 | ||
493 | if (rt2x00dev->rx_status.band == IEEE80211_BAND_2GHZ) { | 511 | if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) { |
494 | rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &eeprom); | 512 | rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &eeprom); |
495 | offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET0); | 513 | offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET0); |
496 | offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET1); | 514 | offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET1); |
@@ -569,6 +587,148 @@ void rt2800_process_rxwi(struct queue_entry *entry, | |||
569 | } | 587 | } |
570 | EXPORT_SYMBOL_GPL(rt2800_process_rxwi); | 588 | EXPORT_SYMBOL_GPL(rt2800_process_rxwi); |
571 | 589 | ||
590 | static bool rt2800_txdone_entry_check(struct queue_entry *entry, u32 reg) | ||
591 | { | ||
592 | __le32 *txwi; | ||
593 | u32 word; | ||
594 | int wcid, ack, pid; | ||
595 | int tx_wcid, tx_ack, tx_pid; | ||
596 | |||
597 | wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID); | ||
598 | ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED); | ||
599 | pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE); | ||
600 | |||
601 | /* | ||
602 | * This frames has returned with an IO error, | ||
603 | * so the status report is not intended for this | ||
604 | * frame. | ||
605 | */ | ||
606 | if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) { | ||
607 | rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); | ||
608 | return false; | ||
609 | } | ||
610 | |||
611 | /* | ||
612 | * Validate if this TX status report is intended for | ||
613 | * this entry by comparing the WCID/ACK/PID fields. | ||
614 | */ | ||
615 | txwi = rt2800_drv_get_txwi(entry); | ||
616 | |||
617 | rt2x00_desc_read(txwi, 1, &word); | ||
618 | tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID); | ||
619 | tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK); | ||
620 | tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID); | ||
621 | |||
622 | if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid)) { | ||
623 | WARNING(entry->queue->rt2x00dev, | ||
624 | "TX status report missed for queue %d entry %d\n", | ||
625 | entry->queue->qid, entry->entry_idx); | ||
626 | rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN); | ||
627 | return false; | ||
628 | } | ||
629 | |||
630 | return true; | ||
631 | } | ||
632 | |||
633 | void rt2800_txdone(struct rt2x00_dev *rt2x00dev) | ||
634 | { | ||
635 | struct data_queue *queue; | ||
636 | struct queue_entry *entry; | ||
637 | __le32 *txwi; | ||
638 | struct txdone_entry_desc txdesc; | ||
639 | u32 word; | ||
640 | u32 reg; | ||
641 | u16 mcs, real_mcs; | ||
642 | u8 pid; | ||
643 | int i; | ||
644 | |||
645 | /* | ||
646 | * TX_STA_FIFO is a stack of X entries, hence read TX_STA_FIFO | ||
647 | * at most X times and also stop processing once the TX_STA_FIFO_VALID | ||
648 | * flag is not set anymore. | ||
649 | * | ||
650 | * The legacy drivers use X=TX_RING_SIZE but state in a comment | ||
651 | * that the TX_STA_FIFO stack has a size of 16. We stick to our | ||
652 | * tx ring size for now. | ||
653 | */ | ||
654 | for (i = 0; i < TX_ENTRIES; i++) { | ||
655 | rt2800_register_read(rt2x00dev, TX_STA_FIFO, ®); | ||
656 | if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID)) | ||
657 | break; | ||
658 | |||
659 | /* | ||
660 | * Skip this entry when it contains an invalid | ||
661 | * queue identication number. | ||
662 | */ | ||
663 | pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE) - 1; | ||
664 | if (pid >= QID_RX) | ||
665 | continue; | ||
666 | |||
667 | queue = rt2x00queue_get_queue(rt2x00dev, pid); | ||
668 | if (unlikely(!queue)) | ||
669 | continue; | ||
670 | |||
671 | /* | ||
672 | * Inside each queue, we process each entry in a chronological | ||
673 | * order. We first check that the queue is not empty. | ||
674 | */ | ||
675 | entry = NULL; | ||
676 | txwi = NULL; | ||
677 | while (!rt2x00queue_empty(queue)) { | ||
678 | entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); | ||
679 | if (rt2800_txdone_entry_check(entry, reg)) | ||
680 | break; | ||
681 | } | ||
682 | |||
683 | if (!entry || rt2x00queue_empty(queue)) | ||
684 | break; | ||
685 | |||
686 | |||
687 | /* | ||
688 | * Obtain the status about this packet. | ||
689 | */ | ||
690 | txdesc.flags = 0; | ||
691 | txwi = rt2800_drv_get_txwi(entry); | ||
692 | rt2x00_desc_read(txwi, 0, &word); | ||
693 | mcs = rt2x00_get_field32(word, TXWI_W0_MCS); | ||
694 | real_mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS); | ||
695 | |||
696 | /* | ||
697 | * Ralink has a retry mechanism using a global fallback | ||
698 | * table. We setup this fallback table to try the immediate | ||
699 | * lower rate for all rates. In the TX_STA_FIFO, the MCS field | ||
700 | * always contains the MCS used for the last transmission, be | ||
701 | * it successful or not. | ||
702 | */ | ||
703 | if (rt2x00_get_field32(reg, TX_STA_FIFO_TX_SUCCESS)) { | ||
704 | /* | ||
705 | * Transmission succeeded. The number of retries is | ||
706 | * mcs - real_mcs | ||
707 | */ | ||
708 | __set_bit(TXDONE_SUCCESS, &txdesc.flags); | ||
709 | txdesc.retry = ((mcs > real_mcs) ? mcs - real_mcs : 0); | ||
710 | } else { | ||
711 | /* | ||
712 | * Transmission failed. The number of retries is | ||
713 | * always 7 in this case (for a total number of 8 | ||
714 | * frames sent). | ||
715 | */ | ||
716 | __set_bit(TXDONE_FAILURE, &txdesc.flags); | ||
717 | txdesc.retry = rt2x00dev->long_retry; | ||
718 | } | ||
719 | |||
720 | /* | ||
721 | * the frame was retried at least once | ||
722 | * -> hw used fallback rates | ||
723 | */ | ||
724 | if (txdesc.retry) | ||
725 | __set_bit(TXDONE_FALLBACK, &txdesc.flags); | ||
726 | |||
727 | rt2x00lib_txdone(entry, &txdesc); | ||
728 | } | ||
729 | } | ||
730 | EXPORT_SYMBOL_GPL(rt2800_txdone); | ||
731 | |||
572 | void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) | 732 | void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) |
573 | { | 733 | { |
574 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; | 734 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; |
@@ -600,7 +760,7 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) | |||
600 | /* | 760 | /* |
601 | * Add the TXWI for the beacon to the skb. | 761 | * Add the TXWI for the beacon to the skb. |
602 | */ | 762 | */ |
603 | rt2800_write_txwi((__le32 *)entry->skb->data, txdesc); | 763 | rt2800_write_tx_data(entry, txdesc); |
604 | 764 | ||
605 | /* | 765 | /* |
606 | * Dump beacon to userspace through debugfs. | 766 | * Dump beacon to userspace through debugfs. |
@@ -975,19 +1135,23 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, | |||
975 | } | 1135 | } |
976 | 1136 | ||
977 | if (flags & CONFIG_UPDATE_MAC) { | 1137 | if (flags & CONFIG_UPDATE_MAC) { |
978 | reg = le32_to_cpu(conf->mac[1]); | 1138 | if (!is_zero_ether_addr((const u8 *)conf->mac)) { |
979 | rt2x00_set_field32(®, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff); | 1139 | reg = le32_to_cpu(conf->mac[1]); |
980 | conf->mac[1] = cpu_to_le32(reg); | 1140 | rt2x00_set_field32(®, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff); |
1141 | conf->mac[1] = cpu_to_le32(reg); | ||
1142 | } | ||
981 | 1143 | ||
982 | rt2800_register_multiwrite(rt2x00dev, MAC_ADDR_DW0, | 1144 | rt2800_register_multiwrite(rt2x00dev, MAC_ADDR_DW0, |
983 | conf->mac, sizeof(conf->mac)); | 1145 | conf->mac, sizeof(conf->mac)); |
984 | } | 1146 | } |
985 | 1147 | ||
986 | if (flags & CONFIG_UPDATE_BSSID) { | 1148 | if (flags & CONFIG_UPDATE_BSSID) { |
987 | reg = le32_to_cpu(conf->bssid[1]); | 1149 | if (!is_zero_ether_addr((const u8 *)conf->bssid)) { |
988 | rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_ID_MASK, 3); | 1150 | reg = le32_to_cpu(conf->bssid[1]); |
989 | rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 7); | 1151 | rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_ID_MASK, 3); |
990 | conf->bssid[1] = cpu_to_le32(reg); | 1152 | rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 7); |
1153 | conf->bssid[1] = cpu_to_le32(reg); | ||
1154 | } | ||
991 | 1155 | ||
992 | rt2800_register_multiwrite(rt2x00dev, MAC_BSSID_DW0, | 1156 | rt2800_register_multiwrite(rt2x00dev, MAC_BSSID_DW0, |
993 | conf->bssid, sizeof(conf->bssid)); | 1157 | conf->bssid, sizeof(conf->bssid)); |
@@ -995,38 +1159,50 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, | |||
995 | } | 1159 | } |
996 | EXPORT_SYMBOL_GPL(rt2800_config_intf); | 1160 | EXPORT_SYMBOL_GPL(rt2800_config_intf); |
997 | 1161 | ||
998 | void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp) | 1162 | void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp, |
1163 | u32 changed) | ||
999 | { | 1164 | { |
1000 | u32 reg; | 1165 | u32 reg; |
1001 | 1166 | ||
1002 | rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, ®); | 1167 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { |
1003 | rt2x00_set_field32(®, AUTO_RSP_CFG_BAC_ACK_POLICY, | 1168 | rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, ®); |
1004 | !!erp->short_preamble); | 1169 | rt2x00_set_field32(®, AUTO_RSP_CFG_BAC_ACK_POLICY, |
1005 | rt2x00_set_field32(®, AUTO_RSP_CFG_AR_PREAMBLE, | 1170 | !!erp->short_preamble); |
1006 | !!erp->short_preamble); | 1171 | rt2x00_set_field32(®, AUTO_RSP_CFG_AR_PREAMBLE, |
1007 | rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg); | 1172 | !!erp->short_preamble); |
1173 | rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg); | ||
1174 | } | ||
1008 | 1175 | ||
1009 | rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); | 1176 | if (changed & BSS_CHANGED_ERP_CTS_PROT) { |
1010 | rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, | 1177 | rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); |
1011 | erp->cts_protection ? 2 : 0); | 1178 | rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, |
1012 | rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); | 1179 | erp->cts_protection ? 2 : 0); |
1180 | rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); | ||
1181 | } | ||
1013 | 1182 | ||
1014 | rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, | 1183 | if (changed & BSS_CHANGED_BASIC_RATES) { |
1015 | erp->basic_rates); | 1184 | rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, |
1016 | rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); | 1185 | erp->basic_rates); |
1186 | rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); | ||
1187 | } | ||
1017 | 1188 | ||
1018 | rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG, ®); | 1189 | if (changed & BSS_CHANGED_ERP_SLOT) { |
1019 | rt2x00_set_field32(®, BKOFF_SLOT_CFG_SLOT_TIME, erp->slot_time); | 1190 | rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG, ®); |
1020 | rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg); | 1191 | rt2x00_set_field32(®, BKOFF_SLOT_CFG_SLOT_TIME, |
1192 | erp->slot_time); | ||
1193 | rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg); | ||
1021 | 1194 | ||
1022 | rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, ®); | 1195 | rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, ®); |
1023 | rt2x00_set_field32(®, XIFS_TIME_CFG_EIFS, erp->eifs); | 1196 | rt2x00_set_field32(®, XIFS_TIME_CFG_EIFS, erp->eifs); |
1024 | rt2800_register_write(rt2x00dev, XIFS_TIME_CFG, reg); | 1197 | rt2800_register_write(rt2x00dev, XIFS_TIME_CFG, reg); |
1198 | } | ||
1025 | 1199 | ||
1026 | rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); | 1200 | if (changed & BSS_CHANGED_BEACON_INT) { |
1027 | rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, | 1201 | rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); |
1028 | erp->beacon_int * 16); | 1202 | rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, |
1029 | rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); | 1203 | erp->beacon_int * 16); |
1204 | rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); | ||
1205 | } | ||
1030 | } | 1206 | } |
1031 | EXPORT_SYMBOL_GPL(rt2800_config_erp); | 1207 | EXPORT_SYMBOL_GPL(rt2800_config_erp); |
1032 | 1208 | ||
@@ -1120,27 +1296,23 @@ static void rt2800_config_channel_rf2xxx(struct rt2x00_dev *rt2x00dev, | |||
1120 | * double meaning, and we should set a 7DBm boost flag. | 1296 | * double meaning, and we should set a 7DBm boost flag. |
1121 | */ | 1297 | */ |
1122 | rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A_7DBM_BOOST, | 1298 | rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A_7DBM_BOOST, |
1123 | (info->tx_power1 >= 0)); | 1299 | (info->default_power1 >= 0)); |
1124 | 1300 | ||
1125 | if (info->tx_power1 < 0) | 1301 | if (info->default_power1 < 0) |
1126 | info->tx_power1 += 7; | 1302 | info->default_power1 += 7; |
1127 | 1303 | ||
1128 | rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A, | 1304 | rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A, info->default_power1); |
1129 | TXPOWER_A_TO_DEV(info->tx_power1)); | ||
1130 | 1305 | ||
1131 | rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A_7DBM_BOOST, | 1306 | rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A_7DBM_BOOST, |
1132 | (info->tx_power2 >= 0)); | 1307 | (info->default_power2 >= 0)); |
1133 | 1308 | ||
1134 | if (info->tx_power2 < 0) | 1309 | if (info->default_power2 < 0) |
1135 | info->tx_power2 += 7; | 1310 | info->default_power2 += 7; |
1136 | 1311 | ||
1137 | rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A, | 1312 | rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A, info->default_power2); |
1138 | TXPOWER_A_TO_DEV(info->tx_power2)); | ||
1139 | } else { | 1313 | } else { |
1140 | rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G, | 1314 | rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G, info->default_power1); |
1141 | TXPOWER_G_TO_DEV(info->tx_power1)); | 1315 | rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G, info->default_power2); |
1142 | rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G, | ||
1143 | TXPOWER_G_TO_DEV(info->tx_power2)); | ||
1144 | } | 1316 | } |
1145 | 1317 | ||
1146 | rt2x00_set_field32(&rf->rf4, RF4_HT40, conf_is_ht40(conf)); | 1318 | rt2x00_set_field32(&rf->rf4, RF4_HT40, conf_is_ht40(conf)); |
@@ -1180,13 +1352,11 @@ static void rt2800_config_channel_rf3xxx(struct rt2x00_dev *rt2x00dev, | |||
1180 | rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); | 1352 | rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); |
1181 | 1353 | ||
1182 | rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr); | 1354 | rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr); |
1183 | rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, | 1355 | rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, info->default_power1); |
1184 | TXPOWER_G_TO_DEV(info->tx_power1)); | ||
1185 | rt2800_rfcsr_write(rt2x00dev, 12, rfcsr); | 1356 | rt2800_rfcsr_write(rt2x00dev, 12, rfcsr); |
1186 | 1357 | ||
1187 | rt2800_rfcsr_read(rt2x00dev, 13, &rfcsr); | 1358 | rt2800_rfcsr_read(rt2x00dev, 13, &rfcsr); |
1188 | rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER, | 1359 | rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER, info->default_power2); |
1189 | TXPOWER_G_TO_DEV(info->tx_power2)); | ||
1190 | rt2800_rfcsr_write(rt2x00dev, 13, rfcsr); | 1360 | rt2800_rfcsr_write(rt2x00dev, 13, rfcsr); |
1191 | 1361 | ||
1192 | rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); | 1362 | rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); |
@@ -1210,10 +1380,19 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, | |||
1210 | unsigned int tx_pin; | 1380 | unsigned int tx_pin; |
1211 | u8 bbp; | 1381 | u8 bbp; |
1212 | 1382 | ||
1383 | if (rf->channel <= 14) { | ||
1384 | info->default_power1 = TXPOWER_G_TO_DEV(info->default_power1); | ||
1385 | info->default_power2 = TXPOWER_G_TO_DEV(info->default_power2); | ||
1386 | } else { | ||
1387 | info->default_power1 = TXPOWER_A_TO_DEV(info->default_power1); | ||
1388 | info->default_power2 = TXPOWER_A_TO_DEV(info->default_power2); | ||
1389 | } | ||
1390 | |||
1213 | if (rt2x00_rf(rt2x00dev, RF2020) || | 1391 | if (rt2x00_rf(rt2x00dev, RF2020) || |
1214 | rt2x00_rf(rt2x00dev, RF3020) || | 1392 | rt2x00_rf(rt2x00dev, RF3020) || |
1215 | rt2x00_rf(rt2x00dev, RF3021) || | 1393 | rt2x00_rf(rt2x00dev, RF3021) || |
1216 | rt2x00_rf(rt2x00dev, RF3022)) | 1394 | rt2x00_rf(rt2x00dev, RF3022) || |
1395 | rt2x00_rf(rt2x00dev, RF3052)) | ||
1217 | rt2800_config_channel_rf3xxx(rt2x00dev, conf, rf, info); | 1396 | rt2800_config_channel_rf3xxx(rt2x00dev, conf, rf, info); |
1218 | else | 1397 | else |
1219 | rt2800_config_channel_rf2xxx(rt2x00dev, conf, rf, info); | 1398 | rt2800_config_channel_rf2xxx(rt2x00dev, conf, rf, info); |
@@ -1536,7 +1715,7 @@ EXPORT_SYMBOL_GPL(rt2800_link_tuner); | |||
1536 | /* | 1715 | /* |
1537 | * Initialization functions. | 1716 | * Initialization functions. |
1538 | */ | 1717 | */ |
1539 | int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) | 1718 | static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) |
1540 | { | 1719 | { |
1541 | u32 reg; | 1720 | u32 reg; |
1542 | u16 eeprom; | 1721 | u16 eeprom; |
@@ -1886,6 +2065,14 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) | |||
1886 | rt2800_register_write(rt2x00dev, LG_FBK_CFG1, reg); | 2065 | rt2800_register_write(rt2x00dev, LG_FBK_CFG1, reg); |
1887 | 2066 | ||
1888 | /* | 2067 | /* |
2068 | * Do not force the BA window size, we use the TXWI to set it | ||
2069 | */ | ||
2070 | rt2800_register_read(rt2x00dev, AMPDU_BA_WINSIZE, ®); | ||
2071 | rt2x00_set_field32(®, AMPDU_BA_WINSIZE_FORCE_WINSIZE_ENABLE, 0); | ||
2072 | rt2x00_set_field32(®, AMPDU_BA_WINSIZE_FORCE_WINSIZE, 0); | ||
2073 | rt2800_register_write(rt2x00dev, AMPDU_BA_WINSIZE, reg); | ||
2074 | |||
2075 | /* | ||
1889 | * We must clear the error counters. | 2076 | * We must clear the error counters. |
1890 | * These registers are cleared on read, | 2077 | * These registers are cleared on read, |
1891 | * so we may pass a useless variable to store the value. | 2078 | * so we may pass a useless variable to store the value. |
@@ -1906,7 +2093,6 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) | |||
1906 | 2093 | ||
1907 | return 0; | 2094 | return 0; |
1908 | } | 2095 | } |
1909 | EXPORT_SYMBOL_GPL(rt2800_init_registers); | ||
1910 | 2096 | ||
1911 | static int rt2800_wait_bbp_rf_ready(struct rt2x00_dev *rt2x00dev) | 2097 | static int rt2800_wait_bbp_rf_ready(struct rt2x00_dev *rt2x00dev) |
1912 | { | 2098 | { |
@@ -1949,7 +2135,7 @@ static int rt2800_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) | |||
1949 | return -EACCES; | 2135 | return -EACCES; |
1950 | } | 2136 | } |
1951 | 2137 | ||
1952 | int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) | 2138 | static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) |
1953 | { | 2139 | { |
1954 | unsigned int i; | 2140 | unsigned int i; |
1955 | u16 eeprom; | 2141 | u16 eeprom; |
@@ -2044,7 +2230,6 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) | |||
2044 | 2230 | ||
2045 | return 0; | 2231 | return 0; |
2046 | } | 2232 | } |
2047 | EXPORT_SYMBOL_GPL(rt2800_init_bbp); | ||
2048 | 2233 | ||
2049 | static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev, | 2234 | static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev, |
2050 | bool bw40, u8 rfcsr24, u8 filter_target) | 2235 | bool bw40, u8 rfcsr24, u8 filter_target) |
@@ -2106,7 +2291,7 @@ static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev, | |||
2106 | return rfcsr24; | 2291 | return rfcsr24; |
2107 | } | 2292 | } |
2108 | 2293 | ||
2109 | int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) | 2294 | static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) |
2110 | { | 2295 | { |
2111 | u8 rfcsr; | 2296 | u8 rfcsr; |
2112 | u8 bbp; | 2297 | u8 bbp; |
@@ -2360,7 +2545,100 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) | |||
2360 | 2545 | ||
2361 | return 0; | 2546 | return 0; |
2362 | } | 2547 | } |
2363 | EXPORT_SYMBOL_GPL(rt2800_init_rfcsr); | 2548 | |
2549 | int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev) | ||
2550 | { | ||
2551 | u32 reg; | ||
2552 | u16 word; | ||
2553 | |||
2554 | /* | ||
2555 | * Initialize all registers. | ||
2556 | */ | ||
2557 | if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) || | ||
2558 | rt2800_init_registers(rt2x00dev) || | ||
2559 | rt2800_init_bbp(rt2x00dev) || | ||
2560 | rt2800_init_rfcsr(rt2x00dev))) | ||
2561 | return -EIO; | ||
2562 | |||
2563 | /* | ||
2564 | * Send signal to firmware during boot time. | ||
2565 | */ | ||
2566 | rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0); | ||
2567 | |||
2568 | if (rt2x00_is_usb(rt2x00dev) && | ||
2569 | (rt2x00_rt(rt2x00dev, RT3070) || | ||
2570 | rt2x00_rt(rt2x00dev, RT3071) || | ||
2571 | rt2x00_rt(rt2x00dev, RT3572))) { | ||
2572 | udelay(200); | ||
2573 | rt2800_mcu_request(rt2x00dev, MCU_CURRENT, 0, 0, 0); | ||
2574 | udelay(10); | ||
2575 | } | ||
2576 | |||
2577 | /* | ||
2578 | * Enable RX. | ||
2579 | */ | ||
2580 | rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); | ||
2581 | rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); | ||
2582 | rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0); | ||
2583 | rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); | ||
2584 | |||
2585 | udelay(50); | ||
2586 | |||
2587 | rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); | ||
2588 | rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1); | ||
2589 | rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1); | ||
2590 | rt2x00_set_field32(®, WPDMA_GLO_CFG_WP_DMA_BURST_SIZE, 2); | ||
2591 | rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); | ||
2592 | rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); | ||
2593 | |||
2594 | rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); | ||
2595 | rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); | ||
2596 | rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 1); | ||
2597 | rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); | ||
2598 | |||
2599 | /* | ||
2600 | * Initialize LED control | ||
2601 | */ | ||
2602 | rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word); | ||
2603 | rt2800_mcu_request(rt2x00dev, MCU_LED_1, 0xff, | ||
2604 | word & 0xff, (word >> 8) & 0xff); | ||
2605 | |||
2606 | rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word); | ||
2607 | rt2800_mcu_request(rt2x00dev, MCU_LED_2, 0xff, | ||
2608 | word & 0xff, (word >> 8) & 0xff); | ||
2609 | |||
2610 | rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word); | ||
2611 | rt2800_mcu_request(rt2x00dev, MCU_LED_3, 0xff, | ||
2612 | word & 0xff, (word >> 8) & 0xff); | ||
2613 | |||
2614 | return 0; | ||
2615 | } | ||
2616 | EXPORT_SYMBOL_GPL(rt2800_enable_radio); | ||
2617 | |||
2618 | void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev) | ||
2619 | { | ||
2620 | u32 reg; | ||
2621 | |||
2622 | rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); | ||
2623 | rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); | ||
2624 | rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0); | ||
2625 | rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); | ||
2626 | rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_DMA_BUSY, 0); | ||
2627 | rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); | ||
2628 | rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); | ||
2629 | |||
2630 | /* Wait for DMA, ignore error */ | ||
2631 | rt2800_wait_wpdma_ready(rt2x00dev); | ||
2632 | |||
2633 | rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); | ||
2634 | rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 0); | ||
2635 | rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0); | ||
2636 | rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); | ||
2637 | |||
2638 | rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0); | ||
2639 | rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0); | ||
2640 | } | ||
2641 | EXPORT_SYMBOL_GPL(rt2800_disable_radio); | ||
2364 | 2642 | ||
2365 | int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev) | 2643 | int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev) |
2366 | { | 2644 | { |
@@ -2516,6 +2794,13 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) | |||
2516 | default_lna_gain); | 2794 | default_lna_gain); |
2517 | rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word); | 2795 | rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word); |
2518 | 2796 | ||
2797 | rt2x00_eeprom_read(rt2x00dev, EEPROM_MAX_TX_POWER, &word); | ||
2798 | if (rt2x00_get_field16(word, EEPROM_MAX_TX_POWER_24GHZ) == 0xff) | ||
2799 | rt2x00_set_field16(&word, EEPROM_MAX_TX_POWER_24GHZ, MAX_G_TXPOWER); | ||
2800 | if (rt2x00_get_field16(word, EEPROM_MAX_TX_POWER_5GHZ) == 0xff) | ||
2801 | rt2x00_set_field16(&word, EEPROM_MAX_TX_POWER_5GHZ, MAX_A_TXPOWER); | ||
2802 | rt2x00_eeprom_write(rt2x00dev, EEPROM_MAX_TX_POWER, word); | ||
2803 | |||
2519 | return 0; | 2804 | return 0; |
2520 | } | 2805 | } |
2521 | EXPORT_SYMBOL_GPL(rt2800_validate_eeprom); | 2806 | EXPORT_SYMBOL_GPL(rt2800_validate_eeprom); |
@@ -2755,9 +3040,10 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | |||
2755 | { | 3040 | { |
2756 | struct hw_mode_spec *spec = &rt2x00dev->spec; | 3041 | struct hw_mode_spec *spec = &rt2x00dev->spec; |
2757 | struct channel_info *info; | 3042 | struct channel_info *info; |
2758 | char *tx_power1; | 3043 | char *default_power1; |
2759 | char *tx_power2; | 3044 | char *default_power2; |
2760 | unsigned int i; | 3045 | unsigned int i; |
3046 | unsigned short max_power; | ||
2761 | u16 eeprom; | 3047 | u16 eeprom; |
2762 | 3048 | ||
2763 | /* | 3049 | /* |
@@ -2865,27 +3151,32 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | |||
2865 | /* | 3151 | /* |
2866 | * Create channel information array | 3152 | * Create channel information array |
2867 | */ | 3153 | */ |
2868 | info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); | 3154 | info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL); |
2869 | if (!info) | 3155 | if (!info) |
2870 | return -ENOMEM; | 3156 | return -ENOMEM; |
2871 | 3157 | ||
2872 | spec->channels_info = info; | 3158 | spec->channels_info = info; |
2873 | 3159 | ||
2874 | tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1); | 3160 | rt2x00_eeprom_read(rt2x00dev, EEPROM_MAX_TX_POWER, &eeprom); |
2875 | tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2); | 3161 | max_power = rt2x00_get_field16(eeprom, EEPROM_MAX_TX_POWER_24GHZ); |
3162 | default_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1); | ||
3163 | default_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2); | ||
2876 | 3164 | ||
2877 | for (i = 0; i < 14; i++) { | 3165 | for (i = 0; i < 14; i++) { |
2878 | info[i].tx_power1 = TXPOWER_G_FROM_DEV(tx_power1[i]); | 3166 | info[i].max_power = max_power; |
2879 | info[i].tx_power2 = TXPOWER_G_FROM_DEV(tx_power2[i]); | 3167 | info[i].default_power1 = TXPOWER_G_FROM_DEV(default_power1[i]); |
3168 | info[i].default_power2 = TXPOWER_G_FROM_DEV(default_power2[i]); | ||
2880 | } | 3169 | } |
2881 | 3170 | ||
2882 | if (spec->num_channels > 14) { | 3171 | if (spec->num_channels > 14) { |
2883 | tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1); | 3172 | max_power = rt2x00_get_field16(eeprom, EEPROM_MAX_TX_POWER_5GHZ); |
2884 | tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2); | 3173 | default_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1); |
3174 | default_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2); | ||
2885 | 3175 | ||
2886 | for (i = 14; i < spec->num_channels; i++) { | 3176 | for (i = 14; i < spec->num_channels; i++) { |
2887 | info[i].tx_power1 = TXPOWER_A_FROM_DEV(tx_power1[i]); | 3177 | info[i].max_power = max_power; |
2888 | info[i].tx_power2 = TXPOWER_A_FROM_DEV(tx_power2[i]); | 3178 | info[i].default_power1 = TXPOWER_A_FROM_DEV(default_power1[i]); |
3179 | info[i].default_power2 = TXPOWER_A_FROM_DEV(default_power2[i]); | ||
2889 | } | 3180 | } |
2890 | } | 3181 | } |
2891 | 3182 | ||