diff options
| -rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-4965.c | 252 | ||||
| -rw-r--r-- | drivers/net/wireless/iwlwifi/iwl4965-base.c | 18 |
2 files changed, 231 insertions, 39 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index d44166a599fc..40c795eaabac 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c | |||
| @@ -144,7 +144,7 @@ int iwl4965_hw_rxq_stop(struct iwl4965_priv *priv) | |||
| 144 | return rc; | 144 | return rc; |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | /* stop HW */ | 147 | /* stop Rx DMA */ |
| 148 | iwl4965_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); | 148 | iwl4965_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); |
| 149 | rc = iwl4965_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG, | 149 | rc = iwl4965_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG, |
| 150 | (1 << 24), 1000); | 150 | (1 << 24), 1000); |
| @@ -234,17 +234,22 @@ static int iwl4965_rx_init(struct iwl4965_priv *priv, struct iwl4965_rx_queue *r | |||
| 234 | return rc; | 234 | return rc; |
| 235 | } | 235 | } |
| 236 | 236 | ||
| 237 | /* stop HW */ | 237 | /* Stop Rx DMA */ |
| 238 | iwl4965_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); | 238 | iwl4965_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); |
| 239 | 239 | ||
| 240 | /* Reset driver's Rx queue write index */ | ||
| 240 | iwl4965_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); | 241 | iwl4965_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); |
| 242 | |||
| 243 | /* Tell device where to find RBD circular buffer in DRAM */ | ||
| 241 | iwl4965_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG, | 244 | iwl4965_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG, |
| 242 | rxq->dma_addr >> 8); | 245 | rxq->dma_addr >> 8); |
| 243 | 246 | ||
| 247 | /* Tell device where in DRAM to update its Rx status */ | ||
| 244 | iwl4965_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG, | 248 | iwl4965_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG, |
| 245 | (priv->hw_setting.shared_phys + | 249 | (priv->hw_setting.shared_phys + |
| 246 | offsetof(struct iwl4965_shared, val0)) >> 4); | 250 | offsetof(struct iwl4965_shared, val0)) >> 4); |
| 247 | 251 | ||
| 252 | /* Enable Rx DMA, enable host interrupt, Rx buffer size 4k, 256 RBDs */ | ||
| 248 | iwl4965_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, | 253 | iwl4965_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, |
| 249 | FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | | 254 | FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | |
| 250 | FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | | 255 | FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | |
| @@ -263,6 +268,7 @@ static int iwl4965_rx_init(struct iwl4965_priv *priv, struct iwl4965_rx_queue *r | |||
| 263 | return 0; | 268 | return 0; |
| 264 | } | 269 | } |
| 265 | 270 | ||
| 271 | /* Tell 4965 where to find the "keep warm" buffer */ | ||
| 266 | static int iwl4965_kw_init(struct iwl4965_priv *priv) | 272 | static int iwl4965_kw_init(struct iwl4965_priv *priv) |
| 267 | { | 273 | { |
| 268 | unsigned long flags; | 274 | unsigned long flags; |
| @@ -297,6 +303,11 @@ static int iwl4965_kw_alloc(struct iwl4965_priv *priv) | |||
| 297 | #define CHECK_AND_PRINT(x) ((eeprom_ch->flags & EEPROM_CHANNEL_##x) \ | 303 | #define CHECK_AND_PRINT(x) ((eeprom_ch->flags & EEPROM_CHANNEL_##x) \ |
| 298 | ? # x " " : "") | 304 | ? # x " " : "") |
| 299 | 305 | ||
| 306 | /** | ||
| 307 | * iwl4965_set_fat_chan_info - Copy fat channel info into driver's priv. | ||
| 308 | * | ||
| 309 | * Does not set up a command, or touch hardware. | ||
| 310 | */ | ||
| 300 | int iwl4965_set_fat_chan_info(struct iwl4965_priv *priv, int phymode, u16 channel, | 311 | int iwl4965_set_fat_chan_info(struct iwl4965_priv *priv, int phymode, u16 channel, |
| 301 | const struct iwl4965_eeprom_channel *eeprom_ch, | 312 | const struct iwl4965_eeprom_channel *eeprom_ch, |
| 302 | u8 fat_extension_channel) | 313 | u8 fat_extension_channel) |
| @@ -337,6 +348,9 @@ int iwl4965_set_fat_chan_info(struct iwl4965_priv *priv, int phymode, u16 channe | |||
| 337 | return 0; | 348 | return 0; |
| 338 | } | 349 | } |
| 339 | 350 | ||
| 351 | /** | ||
| 352 | * iwl4965_kw_free - Free the "keep warm" buffer | ||
| 353 | */ | ||
| 340 | static void iwl4965_kw_free(struct iwl4965_priv *priv) | 354 | static void iwl4965_kw_free(struct iwl4965_priv *priv) |
| 341 | { | 355 | { |
| 342 | struct pci_dev *dev = priv->pci_dev; | 356 | struct pci_dev *dev = priv->pci_dev; |
| @@ -363,9 +377,10 @@ static int iwl4965_txq_ctx_reset(struct iwl4965_priv *priv) | |||
| 363 | 377 | ||
| 364 | iwl4965_kw_free(priv); | 378 | iwl4965_kw_free(priv); |
| 365 | 379 | ||
| 380 | /* Free all tx/cmd queues and keep-warm buffer */ | ||
| 366 | iwl4965_hw_txq_ctx_free(priv); | 381 | iwl4965_hw_txq_ctx_free(priv); |
| 367 | 382 | ||
| 368 | /* Tx CMD queue */ | 383 | /* Alloc keep-warm buffer */ |
| 369 | rc = iwl4965_kw_alloc(priv); | 384 | rc = iwl4965_kw_alloc(priv); |
| 370 | if (rc) { | 385 | if (rc) { |
| 371 | IWL_ERROR("Keep Warm allocation failed"); | 386 | IWL_ERROR("Keep Warm allocation failed"); |
| @@ -381,17 +396,20 @@ static int iwl4965_txq_ctx_reset(struct iwl4965_priv *priv) | |||
| 381 | goto error_reset; | 396 | goto error_reset; |
| 382 | } | 397 | } |
| 383 | 398 | ||
| 399 | /* Turn off all Tx DMA channels */ | ||
| 384 | iwl4965_write_prph(priv, KDR_SCD_TXFACT, 0); | 400 | iwl4965_write_prph(priv, KDR_SCD_TXFACT, 0); |
| 385 | iwl4965_release_nic_access(priv); | 401 | iwl4965_release_nic_access(priv); |
| 386 | spin_unlock_irqrestore(&priv->lock, flags); | 402 | spin_unlock_irqrestore(&priv->lock, flags); |
| 387 | 403 | ||
| 404 | /* Tell 4965 where to find the keep-warm buffer */ | ||
| 388 | rc = iwl4965_kw_init(priv); | 405 | rc = iwl4965_kw_init(priv); |
| 389 | if (rc) { | 406 | if (rc) { |
| 390 | IWL_ERROR("kw_init failed\n"); | 407 | IWL_ERROR("kw_init failed\n"); |
| 391 | goto error_reset; | 408 | goto error_reset; |
| 392 | } | 409 | } |
| 393 | 410 | ||
| 394 | /* Tx queue(s) */ | 411 | /* Alloc and init all (default 16) Tx queues, |
| 412 | * including the command queue (#4) */ | ||
| 395 | for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) { | 413 | for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) { |
| 396 | slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? | 414 | slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? |
| 397 | TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; | 415 | TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; |
| @@ -545,6 +563,8 @@ int iwl4965_hw_nic_init(struct iwl4965_priv *priv) | |||
| 545 | iwl4965_rx_queue_update_write_ptr(priv, rxq); | 563 | iwl4965_rx_queue_update_write_ptr(priv, rxq); |
| 546 | 564 | ||
| 547 | spin_unlock_irqrestore(&priv->lock, flags); | 565 | spin_unlock_irqrestore(&priv->lock, flags); |
| 566 | |||
| 567 | /* Allocate and init all Tx and Command queues */ | ||
| 548 | rc = iwl4965_txq_ctx_reset(priv); | 568 | rc = iwl4965_txq_ctx_reset(priv); |
| 549 | if (rc) | 569 | if (rc) |
| 550 | return rc; | 570 | return rc; |
| @@ -593,13 +613,16 @@ int iwl4965_hw_nic_stop_master(struct iwl4965_priv *priv) | |||
| 593 | return rc; | 613 | return rc; |
| 594 | } | 614 | } |
| 595 | 615 | ||
| 616 | /** | ||
| 617 | * iwl4965_hw_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory | ||
| 618 | */ | ||
| 596 | void iwl4965_hw_txq_ctx_stop(struct iwl4965_priv *priv) | 619 | void iwl4965_hw_txq_ctx_stop(struct iwl4965_priv *priv) |
| 597 | { | 620 | { |
| 598 | 621 | ||
| 599 | int txq_id; | 622 | int txq_id; |
| 600 | unsigned long flags; | 623 | unsigned long flags; |
| 601 | 624 | ||
| 602 | /* reset TFD queues */ | 625 | /* Stop each Tx DMA channel, and wait for it to be idle */ |
| 603 | for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) { | 626 | for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) { |
| 604 | spin_lock_irqsave(&priv->lock, flags); | 627 | spin_lock_irqsave(&priv->lock, flags); |
| 605 | if (iwl4965_grab_nic_access(priv)) { | 628 | if (iwl4965_grab_nic_access(priv)) { |
| @@ -617,6 +640,7 @@ void iwl4965_hw_txq_ctx_stop(struct iwl4965_priv *priv) | |||
| 617 | spin_unlock_irqrestore(&priv->lock, flags); | 640 | spin_unlock_irqrestore(&priv->lock, flags); |
| 618 | } | 641 | } |
| 619 | 642 | ||
| 643 | /* Deallocate memory for all Tx queues */ | ||
| 620 | iwl4965_hw_txq_ctx_free(priv); | 644 | iwl4965_hw_txq_ctx_free(priv); |
| 621 | } | 645 | } |
| 622 | 646 | ||
| @@ -1586,16 +1610,23 @@ static void iwl4965_set_wr_ptrs(struct iwl4965_priv *priv, int txq_id, u32 index | |||
| 1586 | iwl4965_write_prph(priv, KDR_SCD_QUEUE_RDPTR(txq_id), index); | 1610 | iwl4965_write_prph(priv, KDR_SCD_QUEUE_RDPTR(txq_id), index); |
| 1587 | } | 1611 | } |
| 1588 | 1612 | ||
| 1589 | /* | 1613 | /** |
| 1590 | * Acquire priv->lock before calling this function ! | 1614 | * iwl4965_tx_queue_set_status - (optionally) start Tx/Cmd queue |
| 1615 | * @tx_fifo_id: Tx DMA/FIFO channel (range 0-7) that the queue will feed | ||
| 1616 | * @scd_retry: (1) Indicates queue will be used in aggregation mode | ||
| 1617 | * | ||
| 1618 | * NOTE: Acquire priv->lock before calling this function ! | ||
| 1591 | */ | 1619 | */ |
| 1592 | static void iwl4965_tx_queue_set_status(struct iwl4965_priv *priv, | 1620 | static void iwl4965_tx_queue_set_status(struct iwl4965_priv *priv, |
| 1593 | struct iwl4965_tx_queue *txq, | 1621 | struct iwl4965_tx_queue *txq, |
| 1594 | int tx_fifo_id, int scd_retry) | 1622 | int tx_fifo_id, int scd_retry) |
| 1595 | { | 1623 | { |
| 1596 | int txq_id = txq->q.id; | 1624 | int txq_id = txq->q.id; |
| 1625 | |||
| 1626 | /* Find out whether to activate Tx queue */ | ||
| 1597 | int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0; | 1627 | int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0; |
| 1598 | 1628 | ||
| 1629 | /* Set up and activate */ | ||
| 1599 | iwl4965_write_prph(priv, KDR_SCD_QUEUE_STATUS_BITS(txq_id), | 1630 | iwl4965_write_prph(priv, KDR_SCD_QUEUE_STATUS_BITS(txq_id), |
| 1600 | (active << SCD_QUEUE_STTS_REG_POS_ACTIVE) | | 1631 | (active << SCD_QUEUE_STTS_REG_POS_ACTIVE) | |
| 1601 | (tx_fifo_id << SCD_QUEUE_STTS_REG_POS_TXF) | | 1632 | (tx_fifo_id << SCD_QUEUE_STTS_REG_POS_TXF) | |
| @@ -1606,7 +1637,7 @@ static void iwl4965_tx_queue_set_status(struct iwl4965_priv *priv, | |||
| 1606 | txq->sched_retry = scd_retry; | 1637 | txq->sched_retry = scd_retry; |
| 1607 | 1638 | ||
| 1608 | IWL_DEBUG_INFO("%s %s Queue %d on AC %d\n", | 1639 | IWL_DEBUG_INFO("%s %s Queue %d on AC %d\n", |
| 1609 | active ? "Activete" : "Deactivate", | 1640 | active ? "Activate" : "Deactivate", |
| 1610 | scd_retry ? "BA" : "AC", txq_id, tx_fifo_id); | 1641 | scd_retry ? "BA" : "AC", txq_id, tx_fifo_id); |
| 1611 | } | 1642 | } |
| 1612 | 1643 | ||
| @@ -1654,6 +1685,7 @@ int iwl4965_alive_notify(struct iwl4965_priv *priv) | |||
| 1654 | return rc; | 1685 | return rc; |
| 1655 | } | 1686 | } |
| 1656 | 1687 | ||
| 1688 | /* Clear 4965's internal Tx Scheduler data base */ | ||
| 1657 | priv->scd_base_addr = iwl4965_read_prph(priv, KDR_SCD_SRAM_BASE_ADDR); | 1689 | priv->scd_base_addr = iwl4965_read_prph(priv, KDR_SCD_SRAM_BASE_ADDR); |
| 1658 | a = priv->scd_base_addr + SCD_CONTEXT_DATA_OFFSET; | 1690 | a = priv->scd_base_addr + SCD_CONTEXT_DATA_OFFSET; |
| 1659 | for (; a < priv->scd_base_addr + SCD_TX_STTS_BITMAP_OFFSET; a += 4) | 1691 | for (; a < priv->scd_base_addr + SCD_TX_STTS_BITMAP_OFFSET; a += 4) |
| @@ -1663,20 +1695,29 @@ int iwl4965_alive_notify(struct iwl4965_priv *priv) | |||
| 1663 | for (; a < sizeof(u16) * priv->hw_setting.max_txq_num; a += 4) | 1695 | for (; a < sizeof(u16) * priv->hw_setting.max_txq_num; a += 4) |
| 1664 | iwl4965_write_targ_mem(priv, a, 0); | 1696 | iwl4965_write_targ_mem(priv, a, 0); |
| 1665 | 1697 | ||
| 1698 | /* Tel 4965 where to find Tx byte count tables */ | ||
| 1666 | iwl4965_write_prph(priv, KDR_SCD_DRAM_BASE_ADDR, | 1699 | iwl4965_write_prph(priv, KDR_SCD_DRAM_BASE_ADDR, |
| 1667 | (priv->hw_setting.shared_phys + | 1700 | (priv->hw_setting.shared_phys + |
| 1668 | offsetof(struct iwl4965_shared, queues_byte_cnt_tbls)) >> 10); | 1701 | offsetof(struct iwl4965_shared, queues_byte_cnt_tbls)) >> 10); |
| 1702 | |||
| 1703 | /* Disable chain mode for all queues */ | ||
| 1669 | iwl4965_write_prph(priv, KDR_SCD_QUEUECHAIN_SEL, 0); | 1704 | iwl4965_write_prph(priv, KDR_SCD_QUEUECHAIN_SEL, 0); |
| 1670 | 1705 | ||
| 1671 | /* initiate the queues */ | 1706 | /* Initialize each Tx queue (including the command queue) */ |
| 1672 | for (i = 0; i < priv->hw_setting.max_txq_num; i++) { | 1707 | for (i = 0; i < priv->hw_setting.max_txq_num; i++) { |
| 1708 | |||
| 1709 | /* TFD circular buffer read/write indexes */ | ||
| 1673 | iwl4965_write_prph(priv, KDR_SCD_QUEUE_RDPTR(i), 0); | 1710 | iwl4965_write_prph(priv, KDR_SCD_QUEUE_RDPTR(i), 0); |
| 1674 | iwl4965_write_direct32(priv, HBUS_TARG_WRPTR, 0 | (i << 8)); | 1711 | iwl4965_write_direct32(priv, HBUS_TARG_WRPTR, 0 | (i << 8)); |
| 1712 | |||
| 1713 | /* Max Tx Window size for Scheduler-ACK mode */ | ||
| 1675 | iwl4965_write_targ_mem(priv, priv->scd_base_addr + | 1714 | iwl4965_write_targ_mem(priv, priv->scd_base_addr + |
| 1676 | SCD_CONTEXT_QUEUE_OFFSET(i), | 1715 | SCD_CONTEXT_QUEUE_OFFSET(i), |
| 1677 | (SCD_WIN_SIZE << | 1716 | (SCD_WIN_SIZE << |
| 1678 | SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) & | 1717 | SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) & |
| 1679 | SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK); | 1718 | SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK); |
| 1719 | |||
| 1720 | /* Frame limit */ | ||
| 1680 | iwl4965_write_targ_mem(priv, priv->scd_base_addr + | 1721 | iwl4965_write_targ_mem(priv, priv->scd_base_addr + |
| 1681 | SCD_CONTEXT_QUEUE_OFFSET(i) + | 1722 | SCD_CONTEXT_QUEUE_OFFSET(i) + |
| 1682 | sizeof(u32), | 1723 | sizeof(u32), |
| @@ -1688,11 +1729,13 @@ int iwl4965_alive_notify(struct iwl4965_priv *priv) | |||
| 1688 | iwl4965_write_prph(priv, KDR_SCD_INTERRUPT_MASK, | 1729 | iwl4965_write_prph(priv, KDR_SCD_INTERRUPT_MASK, |
| 1689 | (1 << priv->hw_setting.max_txq_num) - 1); | 1730 | (1 << priv->hw_setting.max_txq_num) - 1); |
| 1690 | 1731 | ||
| 1732 | /* Activate all Tx DMA/FIFO channels */ | ||
| 1691 | iwl4965_write_prph(priv, KDR_SCD_TXFACT, | 1733 | iwl4965_write_prph(priv, KDR_SCD_TXFACT, |
| 1692 | SCD_TXFACT_REG_TXFIFO_MASK(0, 7)); | 1734 | SCD_TXFACT_REG_TXFIFO_MASK(0, 7)); |
| 1693 | 1735 | ||
| 1694 | iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); | 1736 | iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); |
| 1695 | /* map qos queues to fifos one-to-one */ | 1737 | |
| 1738 | /* Map each Tx/cmd queue to its corresponding fifo */ | ||
| 1696 | for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) { | 1739 | for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) { |
| 1697 | int ac = default_queue_to_tx_fifo[i]; | 1740 | int ac = default_queue_to_tx_fifo[i]; |
| 1698 | iwl4965_txq_ctx_activate(priv, i); | 1741 | iwl4965_txq_ctx_activate(priv, i); |
| @@ -1705,8 +1748,14 @@ int iwl4965_alive_notify(struct iwl4965_priv *priv) | |||
| 1705 | return 0; | 1748 | return 0; |
| 1706 | } | 1749 | } |
| 1707 | 1750 | ||
| 1751 | /** | ||
| 1752 | * iwl4965_hw_set_hw_setting | ||
| 1753 | * | ||
| 1754 | * Called when initializing driver | ||
| 1755 | */ | ||
| 1708 | int iwl4965_hw_set_hw_setting(struct iwl4965_priv *priv) | 1756 | int iwl4965_hw_set_hw_setting(struct iwl4965_priv *priv) |
| 1709 | { | 1757 | { |
| 1758 | /* Allocate area for Tx byte count tables and Rx queue status */ | ||
| 1710 | priv->hw_setting.shared_virt = | 1759 | priv->hw_setting.shared_virt = |
| 1711 | pci_alloc_consistent(priv->pci_dev, | 1760 | pci_alloc_consistent(priv->pci_dev, |
| 1712 | sizeof(struct iwl4965_shared), | 1761 | sizeof(struct iwl4965_shared), |
| @@ -1741,13 +1790,15 @@ void iwl4965_hw_txq_ctx_free(struct iwl4965_priv *priv) | |||
| 1741 | for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) | 1790 | for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) |
| 1742 | iwl4965_tx_queue_free(priv, &priv->txq[txq_id]); | 1791 | iwl4965_tx_queue_free(priv, &priv->txq[txq_id]); |
| 1743 | 1792 | ||
| 1793 | /* Keep-warm buffer */ | ||
| 1744 | iwl4965_kw_free(priv); | 1794 | iwl4965_kw_free(priv); |
| 1745 | } | 1795 | } |
| 1746 | 1796 | ||
| 1747 | /** | 1797 | /** |
| 1748 | * iwl4965_hw_txq_free_tfd - Free one TFD, those at index [txq->q.read_ptr] | 1798 | * iwl4965_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr] |
| 1749 | * | 1799 | * |
| 1750 | * Does NOT advance any indexes | 1800 | * Does NOT advance any TFD circular buffer read/write indexes |
| 1801 | * Does NOT free the TFD itself (which is within circular buffer) | ||
| 1751 | */ | 1802 | */ |
| 1752 | int iwl4965_hw_txq_free_tfd(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq) | 1803 | int iwl4965_hw_txq_free_tfd(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq) |
| 1753 | { | 1804 | { |
| @@ -1758,12 +1809,11 @@ int iwl4965_hw_txq_free_tfd(struct iwl4965_priv *priv, struct iwl4965_tx_queue * | |||
| 1758 | int counter = 0; | 1809 | int counter = 0; |
| 1759 | int index, is_odd; | 1810 | int index, is_odd; |
| 1760 | 1811 | ||
| 1761 | /* classify bd */ | 1812 | /* Host command buffers stay mapped in memory, nothing to clean */ |
| 1762 | if (txq->q.id == IWL_CMD_QUEUE_NUM) | 1813 | if (txq->q.id == IWL_CMD_QUEUE_NUM) |
| 1763 | /* nothing to cleanup after for host commands */ | ||
| 1764 | return 0; | 1814 | return 0; |
| 1765 | 1815 | ||
| 1766 | /* sanity check */ | 1816 | /* Sanity check on number of chunks */ |
| 1767 | counter = IWL_GET_BITS(*bd, num_tbs); | 1817 | counter = IWL_GET_BITS(*bd, num_tbs); |
| 1768 | if (counter > MAX_NUM_OF_TBS) { | 1818 | if (counter > MAX_NUM_OF_TBS) { |
| 1769 | IWL_ERROR("Too many chunks: %i\n", counter); | 1819 | IWL_ERROR("Too many chunks: %i\n", counter); |
| @@ -1771,8 +1821,8 @@ int iwl4965_hw_txq_free_tfd(struct iwl4965_priv *priv, struct iwl4965_tx_queue * | |||
| 1771 | return 0; | 1821 | return 0; |
| 1772 | } | 1822 | } |
| 1773 | 1823 | ||
| 1774 | /* unmap chunks if any */ | 1824 | /* Unmap chunks, if any. |
| 1775 | 1825 | * TFD info for odd chunks is different format than for even chunks. */ | |
| 1776 | for (i = 0; i < counter; i++) { | 1826 | for (i = 0; i < counter; i++) { |
| 1777 | index = i / 2; | 1827 | index = i / 2; |
| 1778 | is_odd = i & 0x1; | 1828 | is_odd = i & 0x1; |
| @@ -1792,6 +1842,7 @@ int iwl4965_hw_txq_free_tfd(struct iwl4965_priv *priv, struct iwl4965_tx_queue * | |||
| 1792 | IWL_GET_BITS(bd->pa[index], tb1_len), | 1842 | IWL_GET_BITS(bd->pa[index], tb1_len), |
| 1793 | PCI_DMA_TODEVICE); | 1843 | PCI_DMA_TODEVICE); |
| 1794 | 1844 | ||
| 1845 | /* Free SKB, if any, for this chunk */ | ||
| 1795 | if (txq->txb[txq->q.read_ptr].skb[i]) { | 1846 | if (txq->txb[txq->q.read_ptr].skb[i]) { |
| 1796 | struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[i]; | 1847 | struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[i]; |
| 1797 | 1848 | ||
| @@ -1826,6 +1877,17 @@ static s32 iwl4965_math_div_round(s32 num, s32 denom, s32 *res) | |||
| 1826 | return 1; | 1877 | return 1; |
| 1827 | } | 1878 | } |
| 1828 | 1879 | ||
| 1880 | /** | ||
| 1881 | * iwl4965_get_voltage_compensation - Power supply voltage comp for txpower | ||
| 1882 | * | ||
| 1883 | * Determines power supply voltage compensation for txpower calculations. | ||
| 1884 | * Returns number of 1/2-dB steps to subtract from gain table index, | ||
| 1885 | * to compensate for difference between power supply voltage during | ||
| 1886 | * factory measurements, vs. current power supply voltage. | ||
| 1887 | * | ||
| 1888 | * Voltage indication is higher for lower voltage. | ||
| 1889 | * Lower voltage requires more gain (lower gain table index). | ||
| 1890 | */ | ||
| 1829 | static s32 iwl4965_get_voltage_compensation(s32 eeprom_voltage, | 1891 | static s32 iwl4965_get_voltage_compensation(s32 eeprom_voltage, |
| 1830 | s32 current_voltage) | 1892 | s32 current_voltage) |
| 1831 | { | 1893 | { |
| @@ -1913,6 +1975,14 @@ static s32 iwl4965_interpolate_value(s32 x, s32 x1, s32 y1, s32 x2, s32 y2) | |||
| 1913 | } | 1975 | } |
| 1914 | } | 1976 | } |
| 1915 | 1977 | ||
| 1978 | /** | ||
| 1979 | * iwl4965_interpolate_chan - Interpolate factory measurements for one channel | ||
| 1980 | * | ||
| 1981 | * Interpolates factory measurements from the two sample channels within a | ||
| 1982 | * sub-band, to apply to channel of interest. Interpolation is proportional to | ||
| 1983 | * differences in channel frequencies, which is proportional to differences | ||
| 1984 | * in channel number. | ||
| 1985 | */ | ||
| 1916 | static int iwl4965_interpolate_chan(struct iwl4965_priv *priv, u32 channel, | 1986 | static int iwl4965_interpolate_chan(struct iwl4965_priv *priv, u32 channel, |
| 1917 | struct iwl4965_eeprom_calib_ch_info *chan_info) | 1987 | struct iwl4965_eeprom_calib_ch_info *chan_info) |
| 1918 | { | 1988 | { |
| @@ -2681,6 +2751,13 @@ unsigned int iwl4965_hw_get_beacon_cmd(struct iwl4965_priv *priv, | |||
| 2681 | return (sizeof(*tx_beacon_cmd) + frame_size); | 2751 | return (sizeof(*tx_beacon_cmd) + frame_size); |
| 2682 | } | 2752 | } |
| 2683 | 2753 | ||
| 2754 | /* | ||
| 2755 | * Tell 4965 where to find circular buffer of Tx Frame Descriptors for | ||
| 2756 | * given Tx queue, and enable the DMA channel used for that queue. | ||
| 2757 | * | ||
| 2758 | * 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA | ||
| 2759 | * channels supported in hardware. | ||
| 2760 | */ | ||
| 2684 | int iwl4965_hw_tx_queue_init(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq) | 2761 | int iwl4965_hw_tx_queue_init(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq) |
| 2685 | { | 2762 | { |
| 2686 | int rc; | 2763 | int rc; |
| @@ -2694,8 +2771,11 @@ int iwl4965_hw_tx_queue_init(struct iwl4965_priv *priv, struct iwl4965_tx_queue | |||
| 2694 | return rc; | 2771 | return rc; |
| 2695 | } | 2772 | } |
| 2696 | 2773 | ||
| 2774 | /* Circular buffer (TFD queue in DRAM) physical base address */ | ||
| 2697 | iwl4965_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id), | 2775 | iwl4965_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id), |
| 2698 | txq->q.dma_addr >> 8); | 2776 | txq->q.dma_addr >> 8); |
| 2777 | |||
| 2778 | /* Enable DMA channel, using same id as for TFD queue */ | ||
| 2699 | iwl4965_write_direct32( | 2779 | iwl4965_write_direct32( |
| 2700 | priv, IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), | 2780 | priv, IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), |
| 2701 | IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | | 2781 | IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | |
| @@ -2718,6 +2798,7 @@ int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl4965_priv *priv, void *ptr, | |||
| 2718 | struct iwl4965_tfd_frame *tfd = ptr; | 2798 | struct iwl4965_tfd_frame *tfd = ptr; |
| 2719 | u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs); | 2799 | u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs); |
| 2720 | 2800 | ||
| 2801 | /* Each TFD can point to a maximum 20 Tx buffers */ | ||
| 2721 | if ((num_tbs >= MAX_NUM_OF_TBS) || (num_tbs < 0)) { | 2802 | if ((num_tbs >= MAX_NUM_OF_TBS) || (num_tbs < 0)) { |
| 2722 | IWL_ERROR("Error can not send more than %d chunks\n", | 2803 | IWL_ERROR("Error can not send more than %d chunks\n", |
| 2723 | MAX_NUM_OF_TBS); | 2804 | MAX_NUM_OF_TBS); |
| @@ -2759,6 +2840,9 @@ static void iwl4965_hw_card_show_info(struct iwl4965_priv *priv) | |||
| 2759 | #define IWL_TX_CRC_SIZE 4 | 2840 | #define IWL_TX_CRC_SIZE 4 |
| 2760 | #define IWL_TX_DELIMITER_SIZE 4 | 2841 | #define IWL_TX_DELIMITER_SIZE 4 |
| 2761 | 2842 | ||
| 2843 | /** | ||
| 2844 | * iwl4965_tx_queue_update_wr_ptr - Set up entry in Tx byte-count array | ||
| 2845 | */ | ||
| 2762 | int iwl4965_tx_queue_update_wr_ptr(struct iwl4965_priv *priv, | 2846 | int iwl4965_tx_queue_update_wr_ptr(struct iwl4965_priv *priv, |
| 2763 | struct iwl4965_tx_queue *txq, u16 byte_cnt) | 2847 | struct iwl4965_tx_queue *txq, u16 byte_cnt) |
| 2764 | { | 2848 | { |
| @@ -2771,9 +2855,11 @@ int iwl4965_tx_queue_update_wr_ptr(struct iwl4965_priv *priv, | |||
| 2771 | 2855 | ||
| 2772 | len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; | 2856 | len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; |
| 2773 | 2857 | ||
| 2858 | /* Set up byte count within first 256 entries */ | ||
| 2774 | IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. | 2859 | IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. |
| 2775 | tfd_offset[txq->q.write_ptr], byte_cnt, len); | 2860 | tfd_offset[txq->q.write_ptr], byte_cnt, len); |
| 2776 | 2861 | ||
| 2862 | /* If within first 64 entries, duplicate at end */ | ||
| 2777 | if (txq->q.write_ptr < IWL4965_MAX_WIN_SIZE) | 2863 | if (txq->q.write_ptr < IWL4965_MAX_WIN_SIZE) |
| 2778 | IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. | 2864 | IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. |
| 2779 | tfd_offset[IWL4965_QUEUE_SIZE + txq->q.write_ptr], | 2865 | tfd_offset[IWL4965_QUEUE_SIZE + txq->q.write_ptr], |
| @@ -2782,8 +2868,12 @@ int iwl4965_tx_queue_update_wr_ptr(struct iwl4965_priv *priv, | |||
| 2782 | return 0; | 2868 | return 0; |
| 2783 | } | 2869 | } |
| 2784 | 2870 | ||
| 2785 | /* Set up Rx receiver/antenna/chain usage in "staging" RXON image. | 2871 | /** |
| 2786 | * This should not be used for scan command ... it puts data in wrong place. */ | 2872 | * iwl4965_set_rxon_chain - Set up Rx chain usage in "staging" RXON image |
| 2873 | * | ||
| 2874 | * Selects how many and which Rx receivers/antennas/chains to use. | ||
| 2875 | * This should not be used for scan command ... it puts data in wrong place. | ||
| 2876 | */ | ||
| 2787 | void iwl4965_set_rxon_chain(struct iwl4965_priv *priv) | 2877 | void iwl4965_set_rxon_chain(struct iwl4965_priv *priv) |
| 2788 | { | 2878 | { |
| 2789 | u8 is_single = is_single_stream(priv); | 2879 | u8 is_single = is_single_stream(priv); |
| @@ -2931,6 +3021,9 @@ enum HT_STATUS { | |||
| 2931 | BA_STATUS_ACTIVE, | 3021 | BA_STATUS_ACTIVE, |
| 2932 | }; | 3022 | }; |
| 2933 | 3023 | ||
| 3024 | /** | ||
| 3025 | * iwl4964_tl_ba_avail - Find out if an unused aggregation queue is available | ||
| 3026 | */ | ||
| 2934 | static u8 iwl4964_tl_ba_avail(struct iwl4965_priv *priv) | 3027 | static u8 iwl4964_tl_ba_avail(struct iwl4965_priv *priv) |
| 2935 | { | 3028 | { |
| 2936 | int i; | 3029 | int i; |
| @@ -2939,6 +3032,8 @@ static u8 iwl4964_tl_ba_avail(struct iwl4965_priv *priv) | |||
| 2939 | u16 msk; | 3032 | u16 msk; |
| 2940 | 3033 | ||
| 2941 | lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr); | 3034 | lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr); |
| 3035 | |||
| 3036 | /* Find out how many agg queues are in use */ | ||
| 2942 | for (i = 0; i < TID_MAX_LOAD_COUNT ; i++) { | 3037 | for (i = 0; i < TID_MAX_LOAD_COUNT ; i++) { |
| 2943 | msk = 1 << i; | 3038 | msk = 1 << i; |
| 2944 | if ((lq->agg_ctrl.granted_ba & msk) || | 3039 | if ((lq->agg_ctrl.granted_ba & msk) || |
| @@ -3080,6 +3175,9 @@ void iwl4965_turn_off_agg(struct iwl4965_priv *priv, u8 tid) | |||
| 3080 | } | 3175 | } |
| 3081 | } | 3176 | } |
| 3082 | 3177 | ||
| 3178 | /** | ||
| 3179 | * iwl4965_ba_status - Update driver's link quality mgr with tid's HT status | ||
| 3180 | */ | ||
| 3083 | static void iwl4965_ba_status(struct iwl4965_priv *priv, | 3181 | static void iwl4965_ba_status(struct iwl4965_priv *priv, |
| 3084 | u8 tid, enum HT_STATUS status) | 3182 | u8 tid, enum HT_STATUS status) |
| 3085 | { | 3183 | { |
| @@ -3301,11 +3399,12 @@ int iwl4965_get_temperature(const struct iwl4965_priv *priv) | |||
| 3301 | } | 3399 | } |
| 3302 | 3400 | ||
| 3303 | /* | 3401 | /* |
| 3304 | * Temperature is only 23 bits so sign extend out to 32 | 3402 | * Temperature is only 23 bits, so sign extend out to 32. |
| 3305 | * | 3403 | * |
| 3306 | * NOTE If we haven't received a statistics notification yet | 3404 | * NOTE If we haven't received a statistics notification yet |
| 3307 | * with an updated temperature, use R4 provided to us in the | 3405 | * with an updated temperature, use R4 provided to us in the |
| 3308 | * ALIVE response. */ | 3406 | * "initialize" ALIVE response. |
| 3407 | */ | ||
| 3309 | if (!test_bit(STATUS_TEMPERATURE, &priv->status)) | 3408 | if (!test_bit(STATUS_TEMPERATURE, &priv->status)) |
| 3310 | vt = sign_extend(R4, 23); | 3409 | vt = sign_extend(R4, 23); |
| 3311 | else | 3410 | else |
| @@ -4001,6 +4100,11 @@ static void iwl4965_rx_missed_beacon_notif(struct iwl4965_priv *priv, | |||
| 4001 | #ifdef CONFIG_IWL4965_HT | 4100 | #ifdef CONFIG_IWL4965_HT |
| 4002 | #ifdef CONFIG_IWL4965_HT_AGG | 4101 | #ifdef CONFIG_IWL4965_HT_AGG |
| 4003 | 4102 | ||
| 4103 | /** | ||
| 4104 | * iwl4965_set_tx_status - Update driver's record of one Tx frame's status | ||
| 4105 | * | ||
| 4106 | * This will get sent to mac80211. | ||
| 4107 | */ | ||
| 4004 | static void iwl4965_set_tx_status(struct iwl4965_priv *priv, int txq_id, int idx, | 4108 | static void iwl4965_set_tx_status(struct iwl4965_priv *priv, int txq_id, int idx, |
| 4005 | u32 status, u32 retry_count, u32 rate) | 4109 | u32 status, u32 retry_count, u32 rate) |
| 4006 | { | 4110 | { |
| @@ -4013,11 +4117,15 @@ static void iwl4965_set_tx_status(struct iwl4965_priv *priv, int txq_id, int idx | |||
| 4013 | } | 4117 | } |
| 4014 | 4118 | ||
| 4015 | 4119 | ||
| 4120 | /** | ||
| 4121 | * iwl4965_sta_modify_enable_tid_tx - Enable Tx for this TID in station table | ||
| 4122 | */ | ||
| 4016 | static void iwl4965_sta_modify_enable_tid_tx(struct iwl4965_priv *priv, | 4123 | static void iwl4965_sta_modify_enable_tid_tx(struct iwl4965_priv *priv, |
| 4017 | int sta_id, int tid) | 4124 | int sta_id, int tid) |
| 4018 | { | 4125 | { |
| 4019 | unsigned long flags; | 4126 | unsigned long flags; |
| 4020 | 4127 | ||
| 4128 | /* Remove "disable" flag, to enable Tx for this TID */ | ||
| 4021 | spin_lock_irqsave(&priv->sta_lock, flags); | 4129 | spin_lock_irqsave(&priv->sta_lock, flags); |
| 4022 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX; | 4130 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX; |
| 4023 | priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid)); | 4131 | priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid)); |
| @@ -4028,6 +4136,12 @@ static void iwl4965_sta_modify_enable_tid_tx(struct iwl4965_priv *priv, | |||
| 4028 | } | 4136 | } |
| 4029 | 4137 | ||
| 4030 | 4138 | ||
| 4139 | /** | ||
| 4140 | * iwl4965_tx_status_reply_compressed_ba - Update tx status from block-ack | ||
| 4141 | * | ||
| 4142 | * Go through block-ack's bitmap of ACK'd frames, update driver's record of | ||
| 4143 | * ACK vs. not. This gets sent to mac80211, then to rate scaling algo. | ||
| 4144 | */ | ||
| 4031 | static int iwl4965_tx_status_reply_compressed_ba(struct iwl4965_priv *priv, | 4145 | static int iwl4965_tx_status_reply_compressed_ba(struct iwl4965_priv *priv, |
| 4032 | struct iwl4965_ht_agg *agg, | 4146 | struct iwl4965_ht_agg *agg, |
| 4033 | struct iwl4965_compressed_ba_resp* | 4147 | struct iwl4965_compressed_ba_resp* |
| @@ -4044,13 +4158,17 @@ static int iwl4965_tx_status_reply_compressed_ba(struct iwl4965_priv *priv, | |||
| 4044 | IWL_ERROR("Received BA when not expected\n"); | 4158 | IWL_ERROR("Received BA when not expected\n"); |
| 4045 | return -EINVAL; | 4159 | return -EINVAL; |
| 4046 | } | 4160 | } |
| 4161 | |||
| 4162 | /* Mark that the expected block-ack response arrived */ | ||
| 4047 | agg->wait_for_ba = 0; | 4163 | agg->wait_for_ba = 0; |
| 4048 | IWL_DEBUG_TX_REPLY("BA %d %d\n", agg->start_idx, ba_resp->ba_seq_ctl); | 4164 | IWL_DEBUG_TX_REPLY("BA %d %d\n", agg->start_idx, ba_resp->ba_seq_ctl); |
| 4165 | |||
| 4166 | /* Calculate shift to align block-ack bits with our Tx window bits */ | ||
| 4049 | sh = agg->start_idx - SEQ_TO_INDEX(ba_seq_ctl>>4); | 4167 | sh = agg->start_idx - SEQ_TO_INDEX(ba_seq_ctl>>4); |
| 4050 | if (sh < 0) /* tbw something is wrong with indices */ | 4168 | if (sh < 0) /* tbw something is wrong with indices */ |
| 4051 | sh += 0x100; | 4169 | sh += 0x100; |
| 4052 | 4170 | ||
| 4053 | /* don't use 64 bits for now */ | 4171 | /* don't use 64-bit values for now */ |
| 4054 | bitmap0 = resp_bitmap0 >> sh; | 4172 | bitmap0 = resp_bitmap0 >> sh; |
| 4055 | bitmap1 = resp_bitmap1 >> sh; | 4173 | bitmap1 = resp_bitmap1 >> sh; |
| 4056 | bitmap0 |= (resp_bitmap1 & ((1<<sh)|((1<<sh)-1))) << (32 - sh); | 4174 | bitmap0 |= (resp_bitmap1 & ((1<<sh)|((1<<sh)-1))) << (32 - sh); |
| @@ -4061,10 +4179,12 @@ static int iwl4965_tx_status_reply_compressed_ba(struct iwl4965_priv *priv, | |||
| 4061 | } | 4179 | } |
| 4062 | 4180 | ||
| 4063 | /* check for success or failure according to the | 4181 | /* check for success or failure according to the |
| 4064 | * transmitted bitmap and back bitmap */ | 4182 | * transmitted bitmap and block-ack bitmap */ |
| 4065 | bitmap0 &= agg->bitmap0; | 4183 | bitmap0 &= agg->bitmap0; |
| 4066 | bitmap1 &= agg->bitmap1; | 4184 | bitmap1 &= agg->bitmap1; |
| 4067 | 4185 | ||
| 4186 | /* For each frame attempted in aggregation, | ||
| 4187 | * update driver's record of tx frame's status. */ | ||
| 4068 | for (i = 0; i < agg->frame_count ; i++) { | 4188 | for (i = 0; i < agg->frame_count ; i++) { |
| 4069 | int idx = (agg->start_idx + i) & 0xff; | 4189 | int idx = (agg->start_idx + i) & 0xff; |
| 4070 | ack = bitmap0 & (1 << i); | 4190 | ack = bitmap0 & (1 << i); |
| @@ -4080,11 +4200,22 @@ static int iwl4965_tx_status_reply_compressed_ba(struct iwl4965_priv *priv, | |||
| 4080 | return 0; | 4200 | return 0; |
| 4081 | } | 4201 | } |
| 4082 | 4202 | ||
| 4203 | /** | ||
| 4204 | * iwl4965_queue_dec_wrap - Decrement queue index, wrap back to end if needed | ||
| 4205 | * @index -- current index | ||
| 4206 | * @n_bd -- total number of entries in queue (s/b power of 2) | ||
| 4207 | */ | ||
| 4083 | static inline int iwl4965_queue_dec_wrap(int index, int n_bd) | 4208 | static inline int iwl4965_queue_dec_wrap(int index, int n_bd) |
| 4084 | { | 4209 | { |
| 4085 | return (index == 0) ? n_bd - 1 : index - 1; | 4210 | return (index == 0) ? n_bd - 1 : index - 1; |
| 4086 | } | 4211 | } |
| 4087 | 4212 | ||
| 4213 | /** | ||
| 4214 | * iwl4965_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA | ||
| 4215 | * | ||
| 4216 | * Handles block-acknowledge notification from device, which reports success | ||
| 4217 | * of frames sent via aggregation. | ||
| 4218 | */ | ||
| 4088 | static void iwl4965_rx_reply_compressed_ba(struct iwl4965_priv *priv, | 4219 | static void iwl4965_rx_reply_compressed_ba(struct iwl4965_priv *priv, |
| 4089 | struct iwl4965_rx_mem_buffer *rxb) | 4220 | struct iwl4965_rx_mem_buffer *rxb) |
| 4090 | { | 4221 | { |
| @@ -4093,7 +4224,12 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl4965_priv *priv, | |||
| 4093 | int index; | 4224 | int index; |
| 4094 | struct iwl4965_tx_queue *txq = NULL; | 4225 | struct iwl4965_tx_queue *txq = NULL; |
| 4095 | struct iwl4965_ht_agg *agg; | 4226 | struct iwl4965_ht_agg *agg; |
| 4227 | |||
| 4228 | /* "flow" corresponds to Tx queue */ | ||
| 4096 | u16 ba_resp_scd_flow = le16_to_cpu(ba_resp->scd_flow); | 4229 | u16 ba_resp_scd_flow = le16_to_cpu(ba_resp->scd_flow); |
| 4230 | |||
| 4231 | /* "ssn" is start of block-ack Tx window, corresponds to index | ||
| 4232 | * (in Tx queue's circular buffer) of first TFD/frame in window */ | ||
| 4097 | u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn); | 4233 | u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn); |
| 4098 | 4234 | ||
| 4099 | if (ba_resp_scd_flow >= ARRAY_SIZE(priv->txq)) { | 4235 | if (ba_resp_scd_flow >= ARRAY_SIZE(priv->txq)) { |
| @@ -4103,6 +4239,8 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl4965_priv *priv, | |||
| 4103 | 4239 | ||
| 4104 | txq = &priv->txq[ba_resp_scd_flow]; | 4240 | txq = &priv->txq[ba_resp_scd_flow]; |
| 4105 | agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg; | 4241 | agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg; |
| 4242 | |||
| 4243 | /* Find index just before block-ack window */ | ||
| 4106 | index = iwl4965_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); | 4244 | index = iwl4965_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); |
| 4107 | 4245 | ||
| 4108 | /* TODO: Need to get this copy more safely - now good for debug */ | 4246 | /* TODO: Need to get this copy more safely - now good for debug */ |
| @@ -4128,22 +4266,35 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl4965_priv *priv, | |||
| 4128 | agg->bitmap0); | 4266 | agg->bitmap0); |
| 4129 | } | 4267 | } |
| 4130 | */ | 4268 | */ |
| 4269 | |||
| 4270 | /* Update driver's record of ACK vs. not for each frame in window */ | ||
| 4131 | iwl4965_tx_status_reply_compressed_ba(priv, agg, ba_resp); | 4271 | iwl4965_tx_status_reply_compressed_ba(priv, agg, ba_resp); |
| 4132 | /* releases all the TFDs until the SSN */ | 4272 | |
| 4273 | /* Release all TFDs before the SSN, i.e. all TFDs in front of | ||
| 4274 | * block-ack window (we assume that they've been successfully | ||
| 4275 | * transmitted ... if not, it's too late anyway). */ | ||
| 4133 | if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) | 4276 | if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) |
| 4134 | iwl4965_tx_queue_reclaim(priv, ba_resp_scd_flow, index); | 4277 | iwl4965_tx_queue_reclaim(priv, ba_resp_scd_flow, index); |
| 4135 | 4278 | ||
| 4136 | } | 4279 | } |
| 4137 | 4280 | ||
| 4138 | 4281 | ||
| 4282 | /** | ||
| 4283 | * iwl4965_tx_queue_stop_scheduler - Stop queue, but keep configuration | ||
| 4284 | */ | ||
| 4139 | static void iwl4965_tx_queue_stop_scheduler(struct iwl4965_priv *priv, u16 txq_id) | 4285 | static void iwl4965_tx_queue_stop_scheduler(struct iwl4965_priv *priv, u16 txq_id) |
| 4140 | { | 4286 | { |
| 4287 | /* Simply stop the queue, but don't change any configuration; | ||
| 4288 | * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */ | ||
| 4141 | iwl4965_write_prph(priv, | 4289 | iwl4965_write_prph(priv, |
| 4142 | KDR_SCD_QUEUE_STATUS_BITS(txq_id), | 4290 | KDR_SCD_QUEUE_STATUS_BITS(txq_id), |
| 4143 | (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)| | 4291 | (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)| |
| 4144 | (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); | 4292 | (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); |
| 4145 | } | 4293 | } |
| 4146 | 4294 | ||
| 4295 | /** | ||
| 4296 | * iwl4965_tx_queue_set_q2ratid - Map unique receiver/tid combination to a queue | ||
| 4297 | */ | ||
| 4147 | static int iwl4965_tx_queue_set_q2ratid(struct iwl4965_priv *priv, u16 ra_tid, | 4298 | static int iwl4965_tx_queue_set_q2ratid(struct iwl4965_priv *priv, u16 ra_tid, |
| 4148 | u16 txq_id) | 4299 | u16 txq_id) |
| 4149 | { | 4300 | { |
| @@ -4169,7 +4320,10 @@ static int iwl4965_tx_queue_set_q2ratid(struct iwl4965_priv *priv, u16 ra_tid, | |||
| 4169 | } | 4320 | } |
| 4170 | 4321 | ||
| 4171 | /** | 4322 | /** |
| 4172 | * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID | 4323 | * iwl4965_tx_queue_agg_enable - Set up & enable aggregation for selected queue |
| 4324 | * | ||
| 4325 | * NOTE: txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID, | ||
| 4326 | * i.e. it must be one of the higher queues used for aggregation | ||
| 4173 | */ | 4327 | */ |
| 4174 | static int iwl4965_tx_queue_agg_enable(struct iwl4965_priv *priv, int txq_id, | 4328 | static int iwl4965_tx_queue_agg_enable(struct iwl4965_priv *priv, int txq_id, |
| 4175 | int tx_fifo, int sta_id, int tid, | 4329 | int tx_fifo, int sta_id, int tid, |
| @@ -4185,6 +4339,7 @@ static int iwl4965_tx_queue_agg_enable(struct iwl4965_priv *priv, int txq_id, | |||
| 4185 | 4339 | ||
| 4186 | ra_tid = BUILD_RAxTID(sta_id, tid); | 4340 | ra_tid = BUILD_RAxTID(sta_id, tid); |
| 4187 | 4341 | ||
| 4342 | /* Modify device's station table to Tx this TID */ | ||
| 4188 | iwl4965_sta_modify_enable_tid_tx(priv, sta_id, tid); | 4343 | iwl4965_sta_modify_enable_tid_tx(priv, sta_id, tid); |
| 4189 | 4344 | ||
| 4190 | spin_lock_irqsave(&priv->lock, flags); | 4345 | spin_lock_irqsave(&priv->lock, flags); |
| @@ -4194,19 +4349,22 @@ static int iwl4965_tx_queue_agg_enable(struct iwl4965_priv *priv, int txq_id, | |||
| 4194 | return rc; | 4349 | return rc; |
| 4195 | } | 4350 | } |
| 4196 | 4351 | ||
| 4352 | /* Stop this Tx queue before configuring it */ | ||
| 4197 | iwl4965_tx_queue_stop_scheduler(priv, txq_id); | 4353 | iwl4965_tx_queue_stop_scheduler(priv, txq_id); |
| 4198 | 4354 | ||
| 4355 | /* Map receiver-address / traffic-ID to this queue */ | ||
| 4199 | iwl4965_tx_queue_set_q2ratid(priv, ra_tid, txq_id); | 4356 | iwl4965_tx_queue_set_q2ratid(priv, ra_tid, txq_id); |
| 4200 | 4357 | ||
| 4201 | 4358 | /* Set this queue as a chain-building queue */ | |
| 4202 | iwl4965_set_bits_prph(priv, KDR_SCD_QUEUECHAIN_SEL, (1<<txq_id)); | 4359 | iwl4965_set_bits_prph(priv, KDR_SCD_QUEUECHAIN_SEL, (1<<txq_id)); |
| 4203 | 4360 | ||
| 4361 | /* Place first TFD at index corresponding to start sequence number. | ||
| 4362 | * Assumes that ssn_idx is valid (!= 0xFFF) */ | ||
| 4204 | priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff); | 4363 | priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff); |
| 4205 | priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff); | 4364 | priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff); |
| 4206 | |||
| 4207 | /* supposes that ssn_idx is valid (!= 0xFFF) */ | ||
| 4208 | iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx); | 4365 | iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx); |
| 4209 | 4366 | ||
| 4367 | /* Set up Tx window size and frame limit for this queue */ | ||
| 4210 | iwl4965_write_targ_mem(priv, | 4368 | iwl4965_write_targ_mem(priv, |
| 4211 | priv->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(txq_id), | 4369 | priv->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(txq_id), |
| 4212 | (SCD_WIN_SIZE << SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) & | 4370 | (SCD_WIN_SIZE << SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) & |
| @@ -4219,6 +4377,7 @@ static int iwl4965_tx_queue_agg_enable(struct iwl4965_priv *priv, int txq_id, | |||
| 4219 | 4377 | ||
| 4220 | iwl4965_set_bits_prph(priv, KDR_SCD_INTERRUPT_MASK, (1 << txq_id)); | 4378 | iwl4965_set_bits_prph(priv, KDR_SCD_INTERRUPT_MASK, (1 << txq_id)); |
| 4221 | 4379 | ||
| 4380 | /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */ | ||
| 4222 | iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); | 4381 | iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); |
| 4223 | 4382 | ||
| 4224 | iwl4965_release_nic_access(priv); | 4383 | iwl4965_release_nic_access(priv); |
| @@ -4274,14 +4433,16 @@ static int iwl4965_tx_queue_agg_disable(struct iwl4965_priv *priv, u16 txq_id, | |||
| 4274 | /** | 4433 | /** |
| 4275 | * iwl4965_add_station - Initialize a station's hardware rate table | 4434 | * iwl4965_add_station - Initialize a station's hardware rate table |
| 4276 | * | 4435 | * |
| 4277 | * The uCode contains a table of fallback rates and retries per rate | 4436 | * The uCode's station table contains a table of fallback rates |
| 4278 | * for automatic fallback during transmission. | 4437 | * for automatic fallback during transmission. |
| 4279 | * | 4438 | * |
| 4280 | * NOTE: This initializes the table for a single retry per data rate | 4439 | * NOTE: This sets up a default set of values. These will be replaced later |
| 4281 | * which is not optimal. Setting up an intelligent retry per rate | 4440 | * if the driver's iwl-4965-rs rate scaling algorithm is used, instead of |
| 4282 | * requires feedback from transmission, which isn't exposed through | 4441 | * rc80211_simple. |
| 4283 | * rc80211_simple which is what this driver is currently using. | ||
| 4284 | * | 4442 | * |
| 4443 | * NOTE: Run REPLY_ADD_STA command to set up station table entry, before | ||
| 4444 | * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD, | ||
| 4445 | * which requires station table entry to exist). | ||
| 4285 | */ | 4446 | */ |
| 4286 | void iwl4965_add_station(struct iwl4965_priv *priv, const u8 *addr, int is_ap) | 4447 | void iwl4965_add_station(struct iwl4965_priv *priv, const u8 *addr, int is_ap) |
| 4287 | { | 4448 | { |
| @@ -4291,8 +4452,8 @@ void iwl4965_add_station(struct iwl4965_priv *priv, const u8 *addr, int is_ap) | |||
| 4291 | }; | 4452 | }; |
| 4292 | u16 rate_flags; | 4453 | u16 rate_flags; |
| 4293 | 4454 | ||
| 4294 | /* Set up the rate scaling to start at 54M and fallback | 4455 | /* Set up the rate scaling to start at selected rate, fall back |
| 4295 | * all the way to 1M in IEEE order and then spin on IEEE */ | 4456 | * all the way down to 1M in IEEE order, and then spin on 1M */ |
| 4296 | if (is_ap) | 4457 | if (is_ap) |
| 4297 | r = IWL_RATE_54M_INDEX; | 4458 | r = IWL_RATE_54M_INDEX; |
| 4298 | else if (priv->phymode == MODE_IEEE80211A) | 4459 | else if (priv->phymode == MODE_IEEE80211A) |
| @@ -4305,8 +4466,10 @@ void iwl4965_add_station(struct iwl4965_priv *priv, const u8 *addr, int is_ap) | |||
| 4305 | if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) | 4466 | if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) |
| 4306 | rate_flags |= RATE_MCS_CCK_MSK; | 4467 | rate_flags |= RATE_MCS_CCK_MSK; |
| 4307 | 4468 | ||
| 4469 | /* Use Tx antenna B only */ | ||
| 4308 | rate_flags |= RATE_MCS_ANT_B_MSK; | 4470 | rate_flags |= RATE_MCS_ANT_B_MSK; |
| 4309 | rate_flags &= ~RATE_MCS_ANT_A_MSK; | 4471 | rate_flags &= ~RATE_MCS_ANT_A_MSK; |
| 4472 | |||
| 4310 | link_cmd.rs_table[i].rate_n_flags = | 4473 | link_cmd.rs_table[i].rate_n_flags = |
| 4311 | iwl4965_hw_set_rate_n_flags(iwl4965_rates[r].plcp, rate_flags); | 4474 | iwl4965_hw_set_rate_n_flags(iwl4965_rates[r].plcp, rate_flags); |
| 4312 | r = iwl4965_get_prev_ieee_rate(r); | 4475 | r = iwl4965_get_prev_ieee_rate(r); |
| @@ -4374,6 +4537,7 @@ void iwl4965_set_rxon_ht(struct iwl4965_priv *priv, struct sta_ht_info *ht_info) | |||
| 4374 | if (!ht_info->is_ht) | 4537 | if (!ht_info->is_ht) |
| 4375 | return; | 4538 | return; |
| 4376 | 4539 | ||
| 4540 | /* Set up channel bandwidth: 20 MHz only, or 20/40 mixed if fat ok */ | ||
| 4377 | if (iwl4965_is_fat_tx_allowed(priv, ht_info)) | 4541 | if (iwl4965_is_fat_tx_allowed(priv, ht_info)) |
| 4378 | rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED_MSK; | 4542 | rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED_MSK; |
| 4379 | else | 4543 | else |
| @@ -4388,7 +4552,7 @@ void iwl4965_set_rxon_ht(struct iwl4965_priv *priv, struct sta_ht_info *ht_info) | |||
| 4388 | return; | 4552 | return; |
| 4389 | } | 4553 | } |
| 4390 | 4554 | ||
| 4391 | /* Note: control channel is oposit to extension channel */ | 4555 | /* Note: control channel is opposite of extension channel */ |
| 4392 | switch (ht_info->extension_chan_offset) { | 4556 | switch (ht_info->extension_chan_offset) { |
| 4393 | case IWL_EXT_CHANNEL_OFFSET_ABOVE: | 4557 | case IWL_EXT_CHANNEL_OFFSET_ABOVE: |
| 4394 | rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); | 4558 | rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); |
| @@ -4514,6 +4678,12 @@ static const u16 default_tid_to_tx_fifo[] = { | |||
| 4514 | IWL_TX_FIFO_AC3 | 4678 | IWL_TX_FIFO_AC3 |
| 4515 | }; | 4679 | }; |
| 4516 | 4680 | ||
| 4681 | /* | ||
| 4682 | * Find first available (lowest unused) Tx Queue, mark it "active". | ||
| 4683 | * Called only when finding queue for aggregation. | ||
| 4684 | * Should never return anything < 7, because they should already | ||
| 4685 | * be in use as EDCA AC (0-3), Command (4), HCCA (5, 6). | ||
| 4686 | */ | ||
| 4517 | static int iwl4965_txq_ctx_activate_free(struct iwl4965_priv *priv) | 4687 | static int iwl4965_txq_ctx_activate_free(struct iwl4965_priv *priv) |
| 4518 | { | 4688 | { |
| 4519 | int txq_id; | 4689 | int txq_id; |
| @@ -4537,6 +4707,7 @@ int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da, u16 tid, | |||
| 4537 | struct iwl4965_tid_data *tid_data; | 4707 | struct iwl4965_tid_data *tid_data; |
| 4538 | DECLARE_MAC_BUF(mac); | 4708 | DECLARE_MAC_BUF(mac); |
| 4539 | 4709 | ||
| 4710 | /* Determine Tx DMA/FIFO channel for this Traffic ID */ | ||
| 4540 | if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) | 4711 | if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) |
| 4541 | tx_fifo = default_tid_to_tx_fifo[tid]; | 4712 | tx_fifo = default_tid_to_tx_fifo[tid]; |
| 4542 | else | 4713 | else |
| @@ -4545,22 +4716,31 @@ int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da, u16 tid, | |||
| 4545 | IWL_WARNING("iwl-AGG iwl4965_mac_ht_tx_agg_start on da=%s" | 4716 | IWL_WARNING("iwl-AGG iwl4965_mac_ht_tx_agg_start on da=%s" |
| 4546 | " tid=%d\n", print_mac(mac, da), tid); | 4717 | " tid=%d\n", print_mac(mac, da), tid); |
| 4547 | 4718 | ||
| 4719 | /* Get index into station table */ | ||
| 4548 | sta_id = iwl4965_hw_find_station(priv, da); | 4720 | sta_id = iwl4965_hw_find_station(priv, da); |
| 4549 | if (sta_id == IWL_INVALID_STATION) | 4721 | if (sta_id == IWL_INVALID_STATION) |
| 4550 | return -ENXIO; | 4722 | return -ENXIO; |
| 4551 | 4723 | ||
| 4724 | /* Find available Tx queue for aggregation */ | ||
| 4552 | txq_id = iwl4965_txq_ctx_activate_free(priv); | 4725 | txq_id = iwl4965_txq_ctx_activate_free(priv); |
| 4553 | if (txq_id == -1) | 4726 | if (txq_id == -1) |
| 4554 | return -ENXIO; | 4727 | return -ENXIO; |
| 4555 | 4728 | ||
| 4556 | spin_lock_irqsave(&priv->sta_lock, flags); | 4729 | spin_lock_irqsave(&priv->sta_lock, flags); |
| 4557 | tid_data = &priv->stations[sta_id].tid[tid]; | 4730 | tid_data = &priv->stations[sta_id].tid[tid]; |
| 4731 | |||
| 4732 | /* Get starting sequence number for 1st frame in block ack window. | ||
| 4733 | * We'll use least signif byte as 1st frame's index into Tx queue. */ | ||
| 4558 | ssn = SEQ_TO_SN(tid_data->seq_number); | 4734 | ssn = SEQ_TO_SN(tid_data->seq_number); |
| 4559 | tid_data->agg.txq_id = txq_id; | 4735 | tid_data->agg.txq_id = txq_id; |
| 4560 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 4736 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
| 4561 | 4737 | ||
| 4562 | *start_seq_num = ssn; | 4738 | *start_seq_num = ssn; |
| 4739 | |||
| 4740 | /* Update driver's link quality manager */ | ||
| 4563 | iwl4965_ba_status(priv, tid, BA_STATUS_ACTIVE); | 4741 | iwl4965_ba_status(priv, tid, BA_STATUS_ACTIVE); |
| 4742 | |||
| 4743 | /* Set up and enable aggregation for selected Tx queue and FIFO */ | ||
| 4564 | return iwl4965_tx_queue_agg_enable(priv, txq_id, tx_fifo, | 4744 | return iwl4965_tx_queue_agg_enable(priv, txq_id, tx_fifo, |
| 4565 | sta_id, tid, ssn); | 4745 | sta_id, tid, ssn); |
| 4566 | } | 4746 | } |
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 74c3d3917fe1..66aa938e316e 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c | |||
| @@ -305,6 +305,9 @@ static int iwl4965_tx_queue_alloc(struct iwl4965_priv *priv, | |||
| 305 | return -ENOMEM; | 305 | return -ENOMEM; |
| 306 | } | 306 | } |
| 307 | 307 | ||
| 308 | /** | ||
| 309 | * iwl4965_tx_queue_init - Allocate and initialize one tx/cmd queue | ||
| 310 | */ | ||
| 308 | int iwl4965_tx_queue_init(struct iwl4965_priv *priv, | 311 | int iwl4965_tx_queue_init(struct iwl4965_priv *priv, |
| 309 | struct iwl4965_tx_queue *txq, int slots_num, u32 txq_id) | 312 | struct iwl4965_tx_queue *txq, int slots_num, u32 txq_id) |
| 310 | { | 313 | { |
| @@ -312,9 +315,14 @@ int iwl4965_tx_queue_init(struct iwl4965_priv *priv, | |||
| 312 | int len; | 315 | int len; |
| 313 | int rc = 0; | 316 | int rc = 0; |
| 314 | 317 | ||
| 315 | /* allocate command space + one big command for scan since scan | 318 | /* |
| 316 | * command is very huge the system will not have two scan at the | 319 | * Alloc buffer array for commands (Tx or other types of commands). |
| 317 | * same time */ | 320 | * For the command queue (#4), allocate command space + one big |
| 321 | * command for scan, since scan command is very huge; the system will | ||
| 322 | * not have two scans at the same time, so only one is needed. | ||
| 323 | * For normal Tx queues (all other queues), no super-size command | ||
| 324 | * space is needed. | ||
| 325 | */ | ||
| 318 | len = sizeof(struct iwl4965_cmd) * slots_num; | 326 | len = sizeof(struct iwl4965_cmd) * slots_num; |
| 319 | if (txq_id == IWL_CMD_QUEUE_NUM) | 327 | if (txq_id == IWL_CMD_QUEUE_NUM) |
| 320 | len += IWL_MAX_SCAN_SIZE; | 328 | len += IWL_MAX_SCAN_SIZE; |
| @@ -322,6 +330,7 @@ int iwl4965_tx_queue_init(struct iwl4965_priv *priv, | |||
| 322 | if (!txq->cmd) | 330 | if (!txq->cmd) |
| 323 | return -ENOMEM; | 331 | return -ENOMEM; |
| 324 | 332 | ||
| 333 | /* Alloc driver data array and TFD circular buffer */ | ||
| 325 | rc = iwl4965_tx_queue_alloc(priv, txq, txq_id); | 334 | rc = iwl4965_tx_queue_alloc(priv, txq, txq_id); |
| 326 | if (rc) { | 335 | if (rc) { |
| 327 | pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); | 336 | pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); |
| @@ -333,8 +342,11 @@ int iwl4965_tx_queue_init(struct iwl4965_priv *priv, | |||
| 333 | /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise | 342 | /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise |
| 334 | * iwl4965_queue_inc_wrap and iwl4965_queue_dec_wrap are broken. */ | 343 | * iwl4965_queue_inc_wrap and iwl4965_queue_dec_wrap are broken. */ |
| 335 | BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); | 344 | BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); |
| 345 | |||
| 346 | /* Initialize queue's high/low-water marks, and head/tail indexes */ | ||
| 336 | iwl4965_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); | 347 | iwl4965_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); |
| 337 | 348 | ||
| 349 | /* Tell device where to find queue */ | ||
| 338 | iwl4965_hw_tx_queue_init(priv, txq); | 350 | iwl4965_hw_tx_queue_init(priv, txq); |
| 339 | 351 | ||
| 340 | return 0; | 352 | return 0; |
