diff options
author | Samuel Ortiz <samuel.ortiz@intel.com> | 2009-01-23 16:45:14 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-01-29 16:01:34 -0500 |
commit | a8e74e2774cd1aecfef0460de07e6e178df89232 (patch) | |
tree | bccf507738fb8753e7ab16a8de9644e9d99ae07c /drivers/net/wireless/iwlwifi/iwl3945-base.c | |
parent | 59606ffa9146538b73bbe1ca1285321cd7474bc0 (diff) |
iwl3945: Use iwlcore TX queue management routines
By adding an additional hw_params (tfd_size) and a new iwl_lib ops (txq_init),
we can now use the iwlcore TX queue management routines.
We had to add a new hw_params because we need to allocate the right DMA buffer
for TFDs, and those have a different sizes depending if you're on 3945 or agn.
Signed-off-by: Samuel Ortiz <samuel.ortiz@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl3945-base.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl3945-base.c | 204 |
1 files changed, 0 insertions, 204 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index bc10e2ae597d..14f95238059a 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c | |||
@@ -93,210 +93,6 @@ struct iwl_mod_params iwl3945_mod_params = { | |||
93 | /* the rest are 0 by default */ | 93 | /* the rest are 0 by default */ |
94 | }; | 94 | }; |
95 | 95 | ||
96 | /*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** | ||
97 | * DMA services | ||
98 | * | ||
99 | * Theory of operation | ||
100 | * | ||
101 | * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer | ||
102 | * of buffer descriptors, each of which points to one or more data buffers for | ||
103 | * the device to read from or fill. Driver and device exchange status of each | ||
104 | * queue via "read" and "write" pointers. Driver keeps minimum of 2 empty | ||
105 | * entries in each circular buffer, to protect against confusing empty and full | ||
106 | * queue states. | ||
107 | * | ||
108 | * The device reads or writes the data in the queues via the device's several | ||
109 | * DMA/FIFO channels. Each queue is mapped to a single DMA channel. | ||
110 | * | ||
111 | * For Tx queue, there are low mark and high mark limits. If, after queuing | ||
112 | * the packet for Tx, free space become < low mark, Tx queue stopped. When | ||
113 | * reclaiming packets (on 'tx done IRQ), if free space become > high mark, | ||
114 | * Tx queue resumed. | ||
115 | * | ||
116 | * The 3945 operates with six queues: One receive queue, one transmit queue | ||
117 | * (#4) for sending commands to the device firmware, and four transmit queues | ||
118 | * (#0-3) for data tx via EDCA. An additional 2 HCCA queues are unused. | ||
119 | ***************************************************/ | ||
120 | |||
121 | /** | ||
122 | * iwl3945_queue_init - Initialize queue's high/low-water and read/write indexes | ||
123 | */ | ||
124 | static int iwl3945_queue_init(struct iwl_priv *priv, struct iwl_queue *q, | ||
125 | int count, int slots_num, u32 id) | ||
126 | { | ||
127 | q->n_bd = count; | ||
128 | q->n_window = slots_num; | ||
129 | q->id = id; | ||
130 | |||
131 | /* count must be power-of-two size, otherwise iwl_queue_inc_wrap | ||
132 | * and iwl_queue_dec_wrap are broken. */ | ||
133 | BUG_ON(!is_power_of_2(count)); | ||
134 | |||
135 | /* slots_num must be power-of-two size, otherwise | ||
136 | * get_cmd_index is broken. */ | ||
137 | BUG_ON(!is_power_of_2(slots_num)); | ||
138 | |||
139 | q->low_mark = q->n_window / 4; | ||
140 | if (q->low_mark < 4) | ||
141 | q->low_mark = 4; | ||
142 | |||
143 | q->high_mark = q->n_window / 8; | ||
144 | if (q->high_mark < 2) | ||
145 | q->high_mark = 2; | ||
146 | |||
147 | q->write_ptr = q->read_ptr = 0; | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | /** | ||
153 | * iwl3945_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue | ||
154 | */ | ||
155 | static int iwl3945_tx_queue_alloc(struct iwl_priv *priv, | ||
156 | struct iwl_tx_queue *txq, u32 id) | ||
157 | { | ||
158 | struct pci_dev *dev = priv->pci_dev; | ||
159 | |||
160 | /* Driver private data, only for Tx (not command) queues, | ||
161 | * not shared with device. */ | ||
162 | if (id != IWL_CMD_QUEUE_NUM) { | ||
163 | txq->txb = kmalloc(sizeof(txq->txb[0]) * | ||
164 | TFD_QUEUE_SIZE_MAX, GFP_KERNEL); | ||
165 | if (!txq->txb) { | ||
166 | IWL_ERR(priv, "kmalloc for auxiliary BD " | ||
167 | "structures failed\n"); | ||
168 | goto error; | ||
169 | } | ||
170 | } else | ||
171 | txq->txb = NULL; | ||
172 | |||
173 | /* Circular buffer of transmit frame descriptors (TFDs), | ||
174 | * shared with device */ | ||
175 | txq->tfds = pci_alloc_consistent(dev, | ||
176 | sizeof(struct iwl3945_tfd) * TFD_QUEUE_SIZE_MAX, | ||
177 | &txq->q.dma_addr); | ||
178 | |||
179 | if (!txq->tfds) { | ||
180 | IWL_ERR(priv, "pci_alloc_consistent(%zd) failed\n", | ||
181 | sizeof(struct iwl3945_tfd) * TFD_QUEUE_SIZE_MAX); | ||
182 | goto error; | ||
183 | } | ||
184 | txq->q.id = id; | ||
185 | |||
186 | return 0; | ||
187 | |||
188 | error: | ||
189 | kfree(txq->txb); | ||
190 | txq->txb = NULL; | ||
191 | |||
192 | return -ENOMEM; | ||
193 | } | ||
194 | |||
195 | /** | ||
196 | * iwl3945_tx_queue_init - Allocate and initialize one tx/cmd queue | ||
197 | */ | ||
198 | int iwl3945_tx_queue_init(struct iwl_priv *priv, | ||
199 | struct iwl_tx_queue *txq, int slots_num, u32 txq_id) | ||
200 | { | ||
201 | int len, i; | ||
202 | int rc = 0; | ||
203 | |||
204 | /* | ||
205 | * Alloc buffer array for commands (Tx or other types of commands). | ||
206 | * For the command queue (#4), allocate command space + one big | ||
207 | * command for scan, since scan command is very huge; the system will | ||
208 | * not have two scans at the same time, so only one is needed. | ||
209 | * For data Tx queues (all other queues), no super-size command | ||
210 | * space is needed. | ||
211 | */ | ||
212 | len = sizeof(struct iwl_cmd); | ||
213 | for (i = 0; i <= slots_num; i++) { | ||
214 | if (i == slots_num) { | ||
215 | if (txq_id == IWL_CMD_QUEUE_NUM) | ||
216 | len += IWL_MAX_SCAN_SIZE; | ||
217 | else | ||
218 | continue; | ||
219 | } | ||
220 | |||
221 | txq->cmd[i] = kmalloc(len, GFP_KERNEL); | ||
222 | if (!txq->cmd[i]) | ||
223 | goto err; | ||
224 | } | ||
225 | |||
226 | /* Alloc driver data array and TFD circular buffer */ | ||
227 | rc = iwl3945_tx_queue_alloc(priv, txq, txq_id); | ||
228 | if (rc) | ||
229 | goto err; | ||
230 | |||
231 | txq->need_update = 0; | ||
232 | |||
233 | /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise | ||
234 | * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */ | ||
235 | BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); | ||
236 | |||
237 | /* Initialize queue high/low-water, head/tail indexes */ | ||
238 | iwl3945_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); | ||
239 | |||
240 | /* Tell device where to find queue, enable DMA channel. */ | ||
241 | iwl3945_hw_tx_queue_init(priv, txq); | ||
242 | |||
243 | return 0; | ||
244 | err: | ||
245 | for (i = 0; i < slots_num; i++) { | ||
246 | kfree(txq->cmd[i]); | ||
247 | txq->cmd[i] = NULL; | ||
248 | } | ||
249 | |||
250 | if (txq_id == IWL_CMD_QUEUE_NUM) { | ||
251 | kfree(txq->cmd[slots_num]); | ||
252 | txq->cmd[slots_num] = NULL; | ||
253 | } | ||
254 | return -ENOMEM; | ||
255 | } | ||
256 | |||
257 | /** | ||
258 | * iwl3945_tx_queue_free - Deallocate DMA queue. | ||
259 | * @txq: Transmit queue to deallocate. | ||
260 | * | ||
261 | * Empty queue by removing and destroying all BD's. | ||
262 | * Free all buffers. | ||
263 | * 0-fill, but do not free "txq" descriptor structure. | ||
264 | */ | ||
265 | void iwl3945_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq) | ||
266 | { | ||
267 | struct iwl_queue *q = &txq->q; | ||
268 | struct pci_dev *dev = priv->pci_dev; | ||
269 | int len, i; | ||
270 | |||
271 | if (q->n_bd == 0) | ||
272 | return; | ||
273 | |||
274 | /* first, empty all BD's */ | ||
275 | for (; q->write_ptr != q->read_ptr; | ||
276 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) | ||
277 | priv->cfg->ops->lib->txq_free_tfd(priv, txq); | ||
278 | |||
279 | len = sizeof(struct iwl_cmd) * q->n_window; | ||
280 | if (q->id == IWL_CMD_QUEUE_NUM) | ||
281 | len += IWL_MAX_SCAN_SIZE; | ||
282 | |||
283 | /* De-alloc array of command/tx buffers */ | ||
284 | for (i = 0; i < TFD_TX_CMD_SLOTS; i++) | ||
285 | kfree(txq->cmd[i]); | ||
286 | |||
287 | /* De-alloc circular buffer of TFDs */ | ||
288 | if (txq->q.n_bd) | ||
289 | pci_free_consistent(dev, sizeof(struct iwl3945_tfd) * | ||
290 | txq->q.n_bd, txq->tfds, txq->q.dma_addr); | ||
291 | |||
292 | /* De-alloc array of per-TFD driver data */ | ||
293 | kfree(txq->txb); | ||
294 | txq->txb = NULL; | ||
295 | |||
296 | /* 0-fill queue descriptor structure */ | ||
297 | memset(txq, 0, sizeof(*txq)); | ||
298 | } | ||
299 | |||
300 | /*************** STATION TABLE MANAGEMENT **** | 96 | /*************** STATION TABLE MANAGEMENT **** |
301 | * mac80211 should be examined to determine if sta_info is duplicating | 97 | * mac80211 should be examined to determine if sta_info is duplicating |
302 | * the functionality provided here | 98 | * the functionality provided here |