iwlwifi: memory allocation optimization

This patch optimizes memory allocation. The cmd member of
iwl_tx_queue was allocated previously as a continuous block
of memory. This patch allocates separate memory chunks for each command
and maps/unmaps these chunks in the run time.

Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Zhu Yi <yi.zhu@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Gregory Greenman and committed by
John W. Linville
da99c4b6 4c43e0d0

+59 -28
+3 -3
drivers/net/wireless/iwlwifi/iwl-5000.c
··· 939 939 len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; 940 940 941 941 if (txq_id != IWL_CMD_QUEUE_NUM) { 942 - sta = txq->cmd[txq->q.write_ptr].cmd.tx.sta_id; 943 - sec_ctl = txq->cmd[txq->q.write_ptr].cmd.tx.sec_ctl; 942 + sta = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id; 943 + sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl; 944 944 945 945 switch (sec_ctl & TX_CMD_SEC_MSK) { 946 946 case TX_CMD_SEC_CCM: ··· 979 979 u8 sta = 0; 980 980 981 981 if (txq_id != IWL_CMD_QUEUE_NUM) 982 - sta = txq->cmd[txq->q.read_ptr].cmd.tx.sta_id; 982 + sta = txq->cmd[txq->q.read_ptr]->cmd.tx.sta_id; 983 983 984 984 shared_data->queues_byte_cnt_tbls[txq_id].tfd_offset[txq->q.read_ptr]. 985 985 val = cpu_to_le16(1 | (sta << 12));
+1 -2
drivers/net/wireless/iwlwifi/iwl-dev.h
··· 135 135 struct iwl_tx_queue { 136 136 struct iwl_queue q; 137 137 struct iwl_tfd_frame *bd; 138 - struct iwl_cmd *cmd; 139 - dma_addr_t dma_addr_cmd; 138 + struct iwl_cmd *cmd[TFD_TX_CMD_SLOTS]; 140 139 struct iwl_tx_info *txb; 141 140 int need_update; 142 141 int sched_retry;
+1 -1
drivers/net/wireless/iwlwifi/iwl-hcmd.c
··· 228 228 * TX cmd queue. Otherwise in case the cmd comes 229 229 * in later, it will possibly set an invalid 230 230 * address (cmd->meta.source). */ 231 - qcmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx]; 231 + qcmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx]; 232 232 qcmd->meta.flags &= ~CMD_WANT_SKB; 233 233 } 234 234 fail:
+54 -22
drivers/net/wireless/iwlwifi/iwl-tx.c
··· 208 208 * Free all buffers. 209 209 * 0-fill, but do not free "txq" descriptor structure. 210 210 */ 211 - static void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq) 211 + static void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) 212 212 { 213 + struct iwl_tx_queue *txq = &priv->txq[txq_id]; 213 214 struct iwl_queue *q = &txq->q; 214 215 struct pci_dev *dev = priv->pci_dev; 215 - int len; 216 + int i, slots_num, len; 216 217 217 218 if (q->n_bd == 0) 218 219 return; ··· 228 227 len += IWL_MAX_SCAN_SIZE; 229 228 230 229 /* De-alloc array of command/tx buffers */ 231 - pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); 230 + slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? 231 + TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; 232 + for (i = 0; i < slots_num; i++) 233 + kfree(txq->cmd[i]); 234 + if (txq_id == IWL_CMD_QUEUE_NUM) 235 + kfree(txq->cmd[slots_num]); 232 236 233 237 /* De-alloc circular buffer of TFDs */ 234 238 if (txq->q.n_bd) ··· 406 400 struct iwl_tx_queue *txq, 407 401 int slots_num, u32 txq_id) 408 402 { 409 - struct pci_dev *dev = priv->pci_dev; 410 - int len; 403 + int i, len; 411 404 int rc = 0; 412 405 413 406 /* ··· 417 412 * For normal Tx queues (all other queues), no super-size command 418 413 * space is needed. 419 414 */ 420 - len = sizeof(struct iwl_cmd) * slots_num; 421 - if (txq_id == IWL_CMD_QUEUE_NUM) 422 - len += IWL_MAX_SCAN_SIZE; 423 - txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd); 424 - if (!txq->cmd) 425 - return -ENOMEM; 415 + len = sizeof(struct iwl_cmd); 416 + for (i = 0; i <= slots_num; i++) { 417 + if (i == slots_num) { 418 + if (txq_id == IWL_CMD_QUEUE_NUM) 419 + len += IWL_MAX_SCAN_SIZE; 420 + else 421 + continue; 422 + } 423 + 424 + txq->cmd[i] = kmalloc(len, GFP_KERNEL | GFP_DMA); 425 + if (!txq->cmd[i]) 426 + return -ENOMEM; 427 + } 426 428 427 429 /* Alloc driver data array and TFD circular buffer */ 428 430 rc = iwl_tx_queue_alloc(priv, txq, txq_id); 429 431 if (rc) { 430 - pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); 432 + for (i = 0; i < slots_num; i++) 433 + kfree(txq->cmd[i]); 431 434 432 435 return -ENOMEM; 433 436 } ··· 464 451 465 452 /* Tx queues */ 466 453 for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) 467 - iwl_tx_queue_free(priv, &priv->txq[txq_id]); 454 + iwl_tx_queue_free(priv, txq_id); 468 455 469 456 /* Keep-warm buffer */ 470 457 iwl_kw_free(priv); ··· 872 859 txq->txb[q->write_ptr].skb[0] = skb; 873 860 874 861 /* Set up first empty entry in queue's array of Tx/cmd buffers */ 875 - out_cmd = &txq->cmd[idx]; 862 + out_cmd = txq->cmd[idx]; 876 863 tx_cmd = &out_cmd->cmd.tx; 877 864 memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); 878 865 memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd)); ··· 912 899 913 900 /* Physical address of this Tx command's header (not MAC header!), 914 901 * within command buffer array. */ 915 - txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx + 916 - offsetof(struct iwl_cmd, hdr); 902 + txcmd_phys = pci_map_single(priv->pci_dev, out_cmd, 903 + sizeof(struct iwl_cmd), PCI_DMA_TODEVICE); 904 + txcmd_phys += offsetof(struct iwl_cmd, hdr); 917 905 918 906 /* Add buffer containing Tx command and MAC(!) header to TFD's 919 907 * first entry */ ··· 1018 1004 u32 idx; 1019 1005 u16 fix_size; 1020 1006 dma_addr_t phys_addr; 1021 - int ret; 1007 + int len, ret; 1022 1008 unsigned long flags; 1023 1009 1024 1010 cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len); ··· 1048 1034 control_flags = (u32 *) tfd; 1049 1035 1050 1036 idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE); 1051 - out_cmd = &txq->cmd[idx]; 1037 + out_cmd = txq->cmd[idx]; 1052 1038 1053 1039 out_cmd->hdr.cmd = cmd->id; 1054 1040 memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta)); ··· 1062 1048 INDEX_TO_SEQ(q->write_ptr)); 1063 1049 if (out_cmd->meta.flags & CMD_SIZE_HUGE) 1064 1050 out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME); 1065 - 1066 - phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx + 1067 - offsetof(struct iwl_cmd, hdr); 1051 + len = (idx == TFD_CMD_SLOTS) ? 1052 + IWL_MAX_SCAN_SIZE : sizeof(struct iwl_cmd); 1053 + phys_addr = pci_map_single(priv->pci_dev, out_cmd, len, 1054 + PCI_DMA_TODEVICE); 1055 + phys_addr += offsetof(struct iwl_cmd, hdr); 1068 1056 iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); 1069 1057 1070 1058 IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, " ··· 1131 1115 { 1132 1116 struct iwl_tx_queue *txq = &priv->txq[txq_id]; 1133 1117 struct iwl_queue *q = &txq->q; 1118 + struct iwl_tfd_frame *bd = &txq->bd[index]; 1119 + dma_addr_t dma_addr; 1120 + int is_odd, buf_len; 1134 1121 int nfreed = 0; 1135 1122 1136 1123 if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) { ··· 1151 1132 q->write_ptr, q->read_ptr); 1152 1133 queue_work(priv->workqueue, &priv->restart); 1153 1134 } 1135 + is_odd = (index/2) & 0x1; 1136 + if (is_odd) { 1137 + dma_addr = IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) | 1138 + (IWL_GET_BITS(bd->pa[index], 1139 + tb2_addr_hi20) << 16); 1140 + buf_len = IWL_GET_BITS(bd->pa[index], tb2_len); 1141 + } else { 1142 + dma_addr = le32_to_cpu(bd->pa[index].tb1_addr); 1143 + buf_len = IWL_GET_BITS(bd->pa[index], tb1_len); 1144 + } 1145 + 1146 + pci_unmap_single(priv->pci_dev, dma_addr, buf_len, 1147 + PCI_DMA_TODEVICE); 1154 1148 nfreed++; 1155 1149 } 1156 1150 } ··· 1195 1163 BUG_ON(txq_id != IWL_CMD_QUEUE_NUM); 1196 1164 1197 1165 cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); 1198 - cmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; 1166 + cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; 1199 1167 1200 1168 /* Input error checking is done when commands are added to queue. */ 1201 1169 if (cmd->meta.flags & CMD_WANT_SKB) {