diff options
Diffstat (limited to 'drivers/dma/ioat/dma_v2.c')
| -rw-r--r-- | drivers/dma/ioat/dma_v2.c | 69 |
1 files changed, 52 insertions, 17 deletions
diff --git a/drivers/dma/ioat/dma_v2.c b/drivers/dma/ioat/dma_v2.c index 8f1f7f05deaa..5f7a500e18d0 100644 --- a/drivers/dma/ioat/dma_v2.c +++ b/drivers/dma/ioat/dma_v2.c | |||
| @@ -239,20 +239,50 @@ void __ioat2_restart_chan(struct ioat2_dma_chan *ioat) | |||
| 239 | __ioat2_start_null_desc(ioat); | 239 | __ioat2_start_null_desc(ioat); |
| 240 | } | 240 | } |
| 241 | 241 | ||
| 242 | static void ioat2_restart_channel(struct ioat2_dma_chan *ioat) | 242 | int ioat2_quiesce(struct ioat_chan_common *chan, unsigned long tmo) |
| 243 | { | 243 | { |
| 244 | struct ioat_chan_common *chan = &ioat->base; | 244 | unsigned long end = jiffies + tmo; |
| 245 | unsigned long phys_complete; | 245 | int err = 0; |
| 246 | u32 status; | 246 | u32 status; |
| 247 | 247 | ||
| 248 | status = ioat_chansts(chan); | 248 | status = ioat_chansts(chan); |
| 249 | if (is_ioat_active(status) || is_ioat_idle(status)) | 249 | if (is_ioat_active(status) || is_ioat_idle(status)) |
| 250 | ioat_suspend(chan); | 250 | ioat_suspend(chan); |
| 251 | while (is_ioat_active(status) || is_ioat_idle(status)) { | 251 | while (is_ioat_active(status) || is_ioat_idle(status)) { |
| 252 | if (end && time_after(jiffies, end)) { | ||
| 253 | err = -ETIMEDOUT; | ||
| 254 | break; | ||
| 255 | } | ||
| 252 | status = ioat_chansts(chan); | 256 | status = ioat_chansts(chan); |
| 253 | cpu_relax(); | 257 | cpu_relax(); |
| 254 | } | 258 | } |
| 255 | 259 | ||
| 260 | return err; | ||
| 261 | } | ||
| 262 | |||
| 263 | int ioat2_reset_sync(struct ioat_chan_common *chan, unsigned long tmo) | ||
| 264 | { | ||
| 265 | unsigned long end = jiffies + tmo; | ||
| 266 | int err = 0; | ||
| 267 | |||
| 268 | ioat_reset(chan); | ||
| 269 | while (ioat_reset_pending(chan)) { | ||
| 270 | if (end && time_after(jiffies, end)) { | ||
| 271 | err = -ETIMEDOUT; | ||
| 272 | break; | ||
| 273 | } | ||
| 274 | cpu_relax(); | ||
| 275 | } | ||
| 276 | |||
| 277 | return err; | ||
| 278 | } | ||
| 279 | |||
| 280 | static void ioat2_restart_channel(struct ioat2_dma_chan *ioat) | ||
| 281 | { | ||
| 282 | struct ioat_chan_common *chan = &ioat->base; | ||
| 283 | unsigned long phys_complete; | ||
| 284 | |||
| 285 | ioat2_quiesce(chan, 0); | ||
| 256 | if (ioat_cleanup_preamble(chan, &phys_complete)) | 286 | if (ioat_cleanup_preamble(chan, &phys_complete)) |
| 257 | __cleanup(ioat, phys_complete); | 287 | __cleanup(ioat, phys_complete); |
| 258 | 288 | ||
| @@ -318,6 +348,19 @@ void ioat2_timer_event(unsigned long data) | |||
| 318 | spin_unlock_bh(&chan->cleanup_lock); | 348 | spin_unlock_bh(&chan->cleanup_lock); |
| 319 | } | 349 | } |
| 320 | 350 | ||
| 351 | static int ioat2_reset_hw(struct ioat_chan_common *chan) | ||
| 352 | { | ||
| 353 | /* throw away whatever the channel was doing and get it initialized */ | ||
| 354 | u32 chanerr; | ||
| 355 | |||
| 356 | ioat2_quiesce(chan, msecs_to_jiffies(100)); | ||
| 357 | |||
| 358 | chanerr = readl(chan->reg_base + IOAT_CHANERR_OFFSET); | ||
| 359 | writel(chanerr, chan->reg_base + IOAT_CHANERR_OFFSET); | ||
| 360 | |||
| 361 | return ioat2_reset_sync(chan, msecs_to_jiffies(200)); | ||
| 362 | } | ||
| 363 | |||
| 321 | /** | 364 | /** |
| 322 | * ioat2_enumerate_channels - find and initialize the device's channels | 365 | * ioat2_enumerate_channels - find and initialize the device's channels |
| 323 | * @device: the device to be enumerated | 366 | * @device: the device to be enumerated |
| @@ -360,6 +403,10 @@ int ioat2_enumerate_channels(struct ioatdma_device *device) | |||
| 360 | (unsigned long) ioat); | 403 | (unsigned long) ioat); |
| 361 | ioat->xfercap_log = xfercap_log; | 404 | ioat->xfercap_log = xfercap_log; |
| 362 | spin_lock_init(&ioat->ring_lock); | 405 | spin_lock_init(&ioat->ring_lock); |
| 406 | if (device->reset_hw(&ioat->base)) { | ||
| 407 | i = 0; | ||
| 408 | break; | ||
| 409 | } | ||
| 363 | } | 410 | } |
| 364 | dma->chancnt = i; | 411 | dma->chancnt = i; |
| 365 | return i; | 412 | return i; |
| @@ -467,7 +514,6 @@ int ioat2_alloc_chan_resources(struct dma_chan *c) | |||
| 467 | struct ioat2_dma_chan *ioat = to_ioat2_chan(c); | 514 | struct ioat2_dma_chan *ioat = to_ioat2_chan(c); |
| 468 | struct ioat_chan_common *chan = &ioat->base; | 515 | struct ioat_chan_common *chan = &ioat->base; |
| 469 | struct ioat_ring_ent **ring; | 516 | struct ioat_ring_ent **ring; |
| 470 | u32 chanerr; | ||
| 471 | int order; | 517 | int order; |
| 472 | 518 | ||
| 473 | /* have we already been set up? */ | 519 | /* have we already been set up? */ |
| @@ -477,12 +523,6 @@ int ioat2_alloc_chan_resources(struct dma_chan *c) | |||
| 477 | /* Setup register to interrupt and write completion status on error */ | 523 | /* Setup register to interrupt and write completion status on error */ |
| 478 | writew(IOAT_CHANCTRL_RUN, chan->reg_base + IOAT_CHANCTRL_OFFSET); | 524 | writew(IOAT_CHANCTRL_RUN, chan->reg_base + IOAT_CHANCTRL_OFFSET); |
| 479 | 525 | ||
| 480 | chanerr = readl(chan->reg_base + IOAT_CHANERR_OFFSET); | ||
| 481 | if (chanerr) { | ||
| 482 | dev_err(to_dev(chan), "CHANERR = %x, clearing\n", chanerr); | ||
| 483 | writel(chanerr, chan->reg_base + IOAT_CHANERR_OFFSET); | ||
| 484 | } | ||
| 485 | |||
| 486 | /* allocate a completion writeback area */ | 526 | /* allocate a completion writeback area */ |
| 487 | /* doing 2 32bit writes to mmio since 1 64b write doesn't work */ | 527 | /* doing 2 32bit writes to mmio since 1 64b write doesn't work */ |
| 488 | chan->completion = pci_pool_alloc(chan->device->completion_pool, | 528 | chan->completion = pci_pool_alloc(chan->device->completion_pool, |
| @@ -746,13 +786,7 @@ void ioat2_free_chan_resources(struct dma_chan *c) | |||
| 746 | tasklet_disable(&chan->cleanup_task); | 786 | tasklet_disable(&chan->cleanup_task); |
| 747 | del_timer_sync(&chan->timer); | 787 | del_timer_sync(&chan->timer); |
| 748 | device->cleanup_tasklet((unsigned long) ioat); | 788 | device->cleanup_tasklet((unsigned long) ioat); |
| 749 | 789 | device->reset_hw(chan); | |
| 750 | /* Delay 100ms after reset to allow internal DMA logic to quiesce | ||
| 751 | * before removing DMA descriptor resources. | ||
| 752 | */ | ||
| 753 | writeb(IOAT_CHANCMD_RESET, | ||
| 754 | chan->reg_base + IOAT_CHANCMD_OFFSET(chan->device->version)); | ||
| 755 | mdelay(100); | ||
| 756 | 790 | ||
| 757 | spin_lock_bh(&ioat->ring_lock); | 791 | spin_lock_bh(&ioat->ring_lock); |
| 758 | descs = ioat2_ring_space(ioat); | 792 | descs = ioat2_ring_space(ioat); |
| @@ -839,6 +873,7 @@ int __devinit ioat2_dma_probe(struct ioatdma_device *device, int dca) | |||
| 839 | int err; | 873 | int err; |
| 840 | 874 | ||
| 841 | device->enumerate_channels = ioat2_enumerate_channels; | 875 | device->enumerate_channels = ioat2_enumerate_channels; |
| 876 | device->reset_hw = ioat2_reset_hw; | ||
| 842 | device->cleanup_tasklet = ioat2_cleanup_tasklet; | 877 | device->cleanup_tasklet = ioat2_cleanup_tasklet; |
| 843 | device->timer_fn = ioat2_timer_event; | 878 | device->timer_fn = ioat2_timer_event; |
| 844 | device->self_test = ioat_dma_self_test; | 879 | device->self_test = ioat_dma_self_test; |
