diff options
author | Dan Williams <dan.j.williams@intel.com> | 2009-09-08 20:55:21 -0400 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2009-09-08 20:55:21 -0400 |
commit | bbb20089a3275a19e475dbc21320c3742e3ca423 (patch) | |
tree | 216fdc1cbef450ca688135c5b8969169482d9a48 /drivers/net/wireless/p54/p54spi.c | |
parent | 3e48e656903e9fd8bc805c6a2c4264d7808d315b (diff) | |
parent | 657a77fa7284d8ae28dfa48f1dc5d919bf5b2843 (diff) |
Merge branch 'dmaengine' into async-tx-next
Conflicts:
crypto/async_tx/async_xor.c
drivers/dma/ioat/dma_v2.h
drivers/dma/ioat/pci.c
drivers/md/raid5.c
Diffstat (limited to 'drivers/net/wireless/p54/p54spi.c')
-rw-r--r-- | drivers/net/wireless/p54/p54spi.c | 175 |
1 files changed, 89 insertions, 86 deletions
diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index d1fe577de3d4..83116baeb110 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c | |||
@@ -96,7 +96,7 @@ static void p54spi_spi_write(struct p54s_priv *priv, u8 address, | |||
96 | spi_message_add_tail(&t[0], &m); | 96 | spi_message_add_tail(&t[0], &m); |
97 | 97 | ||
98 | t[1].tx_buf = buf; | 98 | t[1].tx_buf = buf; |
99 | t[1].len = len; | 99 | t[1].len = len & ~1; |
100 | spi_message_add_tail(&t[1], &m); | 100 | spi_message_add_tail(&t[1], &m); |
101 | 101 | ||
102 | if (len % 2) { | 102 | if (len % 2) { |
@@ -167,15 +167,31 @@ static const struct p54spi_spi_reg p54spi_registers_array[] = | |||
167 | static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits) | 167 | static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits) |
168 | { | 168 | { |
169 | int i; | 169 | int i; |
170 | __le32 buffer; | ||
171 | 170 | ||
172 | for (i = 0; i < 2000; i++) { | 171 | for (i = 0; i < 2000; i++) { |
173 | p54spi_spi_read(priv, reg, &buffer, sizeof(buffer)); | 172 | __le32 buffer = p54spi_read32(priv, reg); |
174 | if (buffer == bits) | 173 | if ((buffer & bits) == bits) |
175 | return 1; | 174 | return 1; |
175 | } | ||
176 | return 0; | ||
177 | } | ||
176 | 178 | ||
177 | msleep(1); | 179 | static int p54spi_spi_write_dma(struct p54s_priv *priv, __le32 base, |
180 | const void *buf, size_t len) | ||
181 | { | ||
182 | if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL, | ||
183 | cpu_to_le32(HOST_ALLOWED))) { | ||
184 | dev_err(&priv->spi->dev, "spi_write_dma not allowed " | ||
185 | "to DMA write.\n"); | ||
186 | return -EAGAIN; | ||
178 | } | 187 | } |
188 | |||
189 | p54spi_write16(priv, SPI_ADRS_DMA_WRITE_CTRL, | ||
190 | cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE)); | ||
191 | |||
192 | p54spi_write16(priv, SPI_ADRS_DMA_WRITE_LEN, cpu_to_le16(len)); | ||
193 | p54spi_write32(priv, SPI_ADRS_DMA_WRITE_BASE, base); | ||
194 | p54spi_spi_write(priv, SPI_ADRS_DMA_DATA, buf, len); | ||
179 | return 0; | 195 | return 0; |
180 | } | 196 | } |
181 | 197 | ||
@@ -228,8 +244,15 @@ static int p54spi_request_eeprom(struct ieee80211_hw *dev) | |||
228 | static int p54spi_upload_firmware(struct ieee80211_hw *dev) | 244 | static int p54spi_upload_firmware(struct ieee80211_hw *dev) |
229 | { | 245 | { |
230 | struct p54s_priv *priv = dev->priv; | 246 | struct p54s_priv *priv = dev->priv; |
231 | unsigned long fw_len, fw_addr; | 247 | unsigned long fw_len, _fw_len; |
232 | long _fw_len; | 248 | unsigned int offset = 0; |
249 | int err = 0; | ||
250 | u8 *fw; | ||
251 | |||
252 | fw_len = priv->firmware->size; | ||
253 | fw = kmemdup(priv->firmware->data, fw_len, GFP_KERNEL); | ||
254 | if (!fw) | ||
255 | return -ENOMEM; | ||
233 | 256 | ||
234 | /* stop the device */ | 257 | /* stop the device */ |
235 | p54spi_write16(priv, SPI_ADRS_DEV_CTRL_STAT, cpu_to_le16( | 258 | p54spi_write16(priv, SPI_ADRS_DEV_CTRL_STAT, cpu_to_le16( |
@@ -244,36 +267,17 @@ static int p54spi_upload_firmware(struct ieee80211_hw *dev) | |||
244 | 267 | ||
245 | msleep(TARGET_BOOT_SLEEP); | 268 | msleep(TARGET_BOOT_SLEEP); |
246 | 269 | ||
247 | fw_addr = ISL38XX_DEV_FIRMWARE_ADDR; | ||
248 | fw_len = priv->firmware->size; | ||
249 | |||
250 | while (fw_len > 0) { | 270 | while (fw_len > 0) { |
251 | _fw_len = min_t(long, fw_len, SPI_MAX_PACKET_SIZE); | 271 | _fw_len = min_t(long, fw_len, SPI_MAX_PACKET_SIZE); |
252 | 272 | ||
253 | p54spi_write16(priv, SPI_ADRS_DMA_WRITE_CTRL, | 273 | err = p54spi_spi_write_dma(priv, cpu_to_le32( |
254 | cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE)); | 274 | ISL38XX_DEV_FIRMWARE_ADDR + offset), |
255 | 275 | (fw + offset), _fw_len); | |
256 | if (p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL, | 276 | if (err < 0) |
257 | cpu_to_le32(HOST_ALLOWED)) == 0) { | 277 | goto out; |
258 | dev_err(&priv->spi->dev, "fw_upload not allowed " | ||
259 | "to DMA write."); | ||
260 | return -EAGAIN; | ||
261 | } | ||
262 | |||
263 | p54spi_write16(priv, SPI_ADRS_DMA_WRITE_LEN, | ||
264 | cpu_to_le16(_fw_len)); | ||
265 | p54spi_write32(priv, SPI_ADRS_DMA_WRITE_BASE, | ||
266 | cpu_to_le32(fw_addr)); | ||
267 | |||
268 | p54spi_spi_write(priv, SPI_ADRS_DMA_DATA, | ||
269 | &priv->firmware->data, _fw_len); | ||
270 | 278 | ||
271 | fw_len -= _fw_len; | 279 | fw_len -= _fw_len; |
272 | fw_addr += _fw_len; | 280 | offset += _fw_len; |
273 | |||
274 | /* FIXME: I think this doesn't work if firmware is large, | ||
275 | * this loop goes to second round. fw->data is not | ||
276 | * increased at all! */ | ||
277 | } | 281 | } |
278 | 282 | ||
279 | BUG_ON(fw_len != 0); | 283 | BUG_ON(fw_len != 0); |
@@ -292,7 +296,10 @@ static int p54spi_upload_firmware(struct ieee80211_hw *dev) | |||
292 | p54spi_write16(priv, SPI_ADRS_DEV_CTRL_STAT, cpu_to_le16( | 296 | p54spi_write16(priv, SPI_ADRS_DEV_CTRL_STAT, cpu_to_le16( |
293 | SPI_CTRL_STAT_HOST_OVERRIDE | SPI_CTRL_STAT_RAM_BOOT)); | 297 | SPI_CTRL_STAT_HOST_OVERRIDE | SPI_CTRL_STAT_RAM_BOOT)); |
294 | msleep(TARGET_BOOT_SLEEP); | 298 | msleep(TARGET_BOOT_SLEEP); |
295 | return 0; | 299 | |
300 | out: | ||
301 | kfree(fw); | ||
302 | return err; | ||
296 | } | 303 | } |
297 | 304 | ||
298 | static void p54spi_power_off(struct p54s_priv *priv) | 305 | static void p54spi_power_off(struct p54s_priv *priv) |
@@ -318,29 +325,21 @@ static inline void p54spi_int_ack(struct p54s_priv *priv, u32 val) | |||
318 | p54spi_write32(priv, SPI_ADRS_HOST_INT_ACK, cpu_to_le32(val)); | 325 | p54spi_write32(priv, SPI_ADRS_HOST_INT_ACK, cpu_to_le32(val)); |
319 | } | 326 | } |
320 | 327 | ||
321 | static void p54spi_wakeup(struct p54s_priv *priv) | 328 | static int p54spi_wakeup(struct p54s_priv *priv) |
322 | { | 329 | { |
323 | unsigned long timeout; | ||
324 | u32 ints; | ||
325 | |||
326 | /* wake the chip */ | 330 | /* wake the chip */ |
327 | p54spi_write32(priv, SPI_ADRS_ARM_INTERRUPTS, | 331 | p54spi_write32(priv, SPI_ADRS_ARM_INTERRUPTS, |
328 | cpu_to_le32(SPI_TARGET_INT_WAKEUP)); | 332 | cpu_to_le32(SPI_TARGET_INT_WAKEUP)); |
329 | 333 | ||
330 | /* And wait for the READY interrupt */ | 334 | /* And wait for the READY interrupt */ |
331 | timeout = jiffies + HZ; | 335 | if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS, |
332 | 336 | cpu_to_le32(SPI_HOST_INT_READY))) { | |
333 | ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); | 337 | dev_err(&priv->spi->dev, "INT_READY timeout\n"); |
334 | while (!(ints & SPI_HOST_INT_READY)) { | 338 | return -EBUSY; |
335 | if (time_after(jiffies, timeout)) | ||
336 | goto out; | ||
337 | ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); | ||
338 | } | 339 | } |
339 | 340 | ||
340 | p54spi_int_ack(priv, SPI_HOST_INT_READY); | 341 | p54spi_int_ack(priv, SPI_HOST_INT_READY); |
341 | 342 | return 0; | |
342 | out: | ||
343 | return; | ||
344 | } | 343 | } |
345 | 344 | ||
346 | static inline void p54spi_sleep(struct p54s_priv *priv) | 345 | static inline void p54spi_sleep(struct p54s_priv *priv) |
@@ -372,27 +371,48 @@ static int p54spi_rx(struct p54s_priv *priv) | |||
372 | { | 371 | { |
373 | struct sk_buff *skb; | 372 | struct sk_buff *skb; |
374 | u16 len; | 373 | u16 len; |
374 | u16 rx_head[2]; | ||
375 | #define READAHEAD_SZ (sizeof(rx_head)-sizeof(u16)) | ||
375 | 376 | ||
376 | p54spi_wakeup(priv); | 377 | if (p54spi_wakeup(priv) < 0) |
377 | 378 | return -EBUSY; | |
378 | /* dummy read to flush SPI DMA controller bug */ | ||
379 | p54spi_read16(priv, SPI_ADRS_GEN_PURP_1); | ||
380 | 379 | ||
381 | len = p54spi_read16(priv, SPI_ADRS_DMA_DATA); | 380 | /* Read data size and first data word in one SPI transaction |
381 | * This is workaround for firmware/DMA bug, | ||
382 | * when first data word gets lost under high load. | ||
383 | */ | ||
384 | p54spi_spi_read(priv, SPI_ADRS_DMA_DATA, rx_head, sizeof(rx_head)); | ||
385 | len = rx_head[0]; | ||
382 | 386 | ||
383 | if (len == 0) { | 387 | if (len == 0) { |
384 | dev_err(&priv->spi->dev, "rx request of zero bytes"); | 388 | p54spi_sleep(priv); |
389 | dev_err(&priv->spi->dev, "rx request of zero bytes\n"); | ||
385 | return 0; | 390 | return 0; |
386 | } | 391 | } |
387 | 392 | ||
388 | skb = dev_alloc_skb(len); | 393 | /* Firmware may insert up to 4 padding bytes after the lmac header, |
394 | * but it does not amend the size of SPI data transfer. | ||
395 | * Such packets has correct data size in header, thus referencing | ||
396 | * past the end of allocated skb. Reserve extra 4 bytes for this case */ | ||
397 | skb = dev_alloc_skb(len + 4); | ||
389 | if (!skb) { | 398 | if (!skb) { |
399 | p54spi_sleep(priv); | ||
390 | dev_err(&priv->spi->dev, "could not alloc skb"); | 400 | dev_err(&priv->spi->dev, "could not alloc skb"); |
391 | return 0; | 401 | return -ENOMEM; |
392 | } | 402 | } |
393 | 403 | ||
394 | p54spi_spi_read(priv, SPI_ADRS_DMA_DATA, skb_put(skb, len), len); | 404 | if (len <= READAHEAD_SZ) { |
405 | memcpy(skb_put(skb, len), rx_head + 1, len); | ||
406 | } else { | ||
407 | memcpy(skb_put(skb, READAHEAD_SZ), rx_head + 1, READAHEAD_SZ); | ||
408 | p54spi_spi_read(priv, SPI_ADRS_DMA_DATA, | ||
409 | skb_put(skb, len - READAHEAD_SZ), | ||
410 | len - READAHEAD_SZ); | ||
411 | } | ||
395 | p54spi_sleep(priv); | 412 | p54spi_sleep(priv); |
413 | /* Put additional bytes to compensate for the possible | ||
414 | * alignment-caused truncation */ | ||
415 | skb_put(skb, 4); | ||
396 | 416 | ||
397 | if (p54_rx(priv->hw, skb) == 0) | 417 | if (p54_rx(priv->hw, skb) == 0) |
398 | dev_kfree_skb(skb); | 418 | dev_kfree_skb(skb); |
@@ -414,39 +434,28 @@ static irqreturn_t p54spi_interrupt(int irq, void *config) | |||
414 | static int p54spi_tx_frame(struct p54s_priv *priv, struct sk_buff *skb) | 434 | static int p54spi_tx_frame(struct p54s_priv *priv, struct sk_buff *skb) |
415 | { | 435 | { |
416 | struct p54_hdr *hdr = (struct p54_hdr *) skb->data; | 436 | struct p54_hdr *hdr = (struct p54_hdr *) skb->data; |
417 | struct p54s_dma_regs dma_regs; | ||
418 | unsigned long timeout; | ||
419 | int ret = 0; | 437 | int ret = 0; |
420 | u32 ints; | ||
421 | |||
422 | p54spi_wakeup(priv); | ||
423 | 438 | ||
424 | dma_regs.cmd = cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE); | 439 | if (p54spi_wakeup(priv) < 0) |
425 | dma_regs.len = cpu_to_le16(skb->len); | 440 | return -EBUSY; |
426 | dma_regs.addr = hdr->req_id; | ||
427 | 441 | ||
428 | p54spi_spi_write(priv, SPI_ADRS_DMA_WRITE_CTRL, &dma_regs, | 442 | ret = p54spi_spi_write_dma(priv, hdr->req_id, skb->data, skb->len); |
429 | sizeof(dma_regs)); | 443 | if (ret < 0) |
430 | 444 | goto out; | |
431 | p54spi_spi_write(priv, SPI_ADRS_DMA_DATA, skb->data, skb->len); | ||
432 | 445 | ||
433 | timeout = jiffies + 2 * HZ; | 446 | if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS, |
434 | ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); | 447 | cpu_to_le32(SPI_HOST_INT_WR_READY))) { |
435 | while (!(ints & SPI_HOST_INT_WR_READY)) { | 448 | dev_err(&priv->spi->dev, "WR_READY timeout\n"); |
436 | if (time_after(jiffies, timeout)) { | 449 | ret = -EAGAIN; |
437 | dev_err(&priv->spi->dev, "WR_READY timeout"); | 450 | goto out; |
438 | ret = -1; | ||
439 | goto out; | ||
440 | } | ||
441 | ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); | ||
442 | } | 451 | } |
443 | 452 | ||
444 | p54spi_int_ack(priv, SPI_HOST_INT_WR_READY); | 453 | p54spi_int_ack(priv, SPI_HOST_INT_WR_READY); |
445 | p54spi_sleep(priv); | ||
446 | 454 | ||
447 | out: | ||
448 | if (FREE_AFTER_TX(skb)) | 455 | if (FREE_AFTER_TX(skb)) |
449 | p54_free_skb(priv->hw, skb); | 456 | p54_free_skb(priv->hw, skb); |
457 | out: | ||
458 | p54spi_sleep(priv); | ||
450 | return ret; | 459 | return ret; |
451 | } | 460 | } |
452 | 461 | ||
@@ -516,8 +525,7 @@ static void p54spi_work(struct work_struct *work) | |||
516 | 525 | ||
517 | mutex_lock(&priv->mutex); | 526 | mutex_lock(&priv->mutex); |
518 | 527 | ||
519 | if (priv->fw_state == FW_STATE_OFF && | 528 | if (priv->fw_state == FW_STATE_OFF) |
520 | priv->fw_state == FW_STATE_RESET) | ||
521 | goto out; | 529 | goto out; |
522 | 530 | ||
523 | ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); | 531 | ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); |
@@ -544,11 +552,6 @@ static void p54spi_work(struct work_struct *work) | |||
544 | } | 552 | } |
545 | 553 | ||
546 | ret = p54spi_wq_tx(priv); | 554 | ret = p54spi_wq_tx(priv); |
547 | if (ret < 0) | ||
548 | goto out; | ||
549 | |||
550 | ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); | ||
551 | |||
552 | out: | 555 | out: |
553 | mutex_unlock(&priv->mutex); | 556 | mutex_unlock(&priv->mutex); |
554 | } | 557 | } |