aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaciej Sosnowski <maciej.sosnowski@intel.com>2008-07-22 13:07:33 -0400
committerDan Williams <dan.j.williams@intel.com>2008-07-22 13:07:33 -0400
commit09177e85d6a0bffac8b55afd28ed8b82bd873f0b (patch)
treece3cb72509cc6c03bfc5d70a3ca0901a44b87fc0
parent2a46fa13d788364c093c4296fe01cae837aa8919 (diff)
I/OAT: Add watchdog/reset functionality to ioatdma
Due to occasional DMA channel hangs observed for I/OAT versions 1.2 and 2.0 a watchdog has been introduced to check every 2 seconds if all channels progress normally. If stuck channel is detected, driver resets it. The reset is done in two parts. The second part is scheduled by the first one to reinitialize the channel after the restart. Signed-off-by: Maciej Sosnowski <maciej.sosnowski@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r--drivers/dma/ioat_dma.c267
-rw-r--r--drivers/dma/ioatdma.h10
2 files changed, 271 insertions, 6 deletions
diff --git a/drivers/dma/ioat_dma.c b/drivers/dma/ioat_dma.c
index 171cad69f318..da572968a7db 100644
--- a/drivers/dma/ioat_dma.c
+++ b/drivers/dma/ioat_dma.c
@@ -32,6 +32,7 @@
32#include <linux/dmaengine.h> 32#include <linux/dmaengine.h>
33#include <linux/delay.h> 33#include <linux/delay.h>
34#include <linux/dma-mapping.h> 34#include <linux/dma-mapping.h>
35#include <linux/workqueue.h>
35#include "ioatdma.h" 36#include "ioatdma.h"
36#include "ioatdma_registers.h" 37#include "ioatdma_registers.h"
37#include "ioatdma_hw.h" 38#include "ioatdma_hw.h"
@@ -41,11 +42,17 @@
41#define to_ioat_desc(lh) container_of(lh, struct ioat_desc_sw, node) 42#define to_ioat_desc(lh) container_of(lh, struct ioat_desc_sw, node)
42#define tx_to_ioat_desc(tx) container_of(tx, struct ioat_desc_sw, async_tx) 43#define tx_to_ioat_desc(tx) container_of(tx, struct ioat_desc_sw, async_tx)
43 44
45#define chan_num(ch) ((int)((ch)->reg_base - (ch)->device->reg_base) / 0x80)
44static int ioat_pending_level = 4; 46static int ioat_pending_level = 4;
45module_param(ioat_pending_level, int, 0644); 47module_param(ioat_pending_level, int, 0644);
46MODULE_PARM_DESC(ioat_pending_level, 48MODULE_PARM_DESC(ioat_pending_level,
47 "high-water mark for pushing ioat descriptors (default: 4)"); 49 "high-water mark for pushing ioat descriptors (default: 4)");
48 50
51#define RESET_DELAY msecs_to_jiffies(100)
52#define WATCHDOG_DELAY round_jiffies(msecs_to_jiffies(2000))
53static void ioat_dma_chan_reset_part2(struct work_struct *work);
54static void ioat_dma_chan_watchdog(struct work_struct *work);
55
49/* internal functions */ 56/* internal functions */
50static void ioat_dma_start_null_desc(struct ioat_dma_chan *ioat_chan); 57static void ioat_dma_start_null_desc(struct ioat_dma_chan *ioat_chan);
51static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan); 58static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan);
@@ -137,6 +144,7 @@ static int ioat_dma_enumerate_channels(struct ioatdma_device *device)
137 ioat_chan->reg_base = device->reg_base + (0x80 * (i + 1)); 144 ioat_chan->reg_base = device->reg_base + (0x80 * (i + 1));
138 ioat_chan->xfercap = xfercap; 145 ioat_chan->xfercap = xfercap;
139 ioat_chan->desccount = 0; 146 ioat_chan->desccount = 0;
147 INIT_DELAYED_WORK(&ioat_chan->work, ioat_dma_chan_reset_part2);
140 if (ioat_chan->device->version != IOAT_VER_1_2) { 148 if (ioat_chan->device->version != IOAT_VER_1_2) {
141 writel(IOAT_DCACTRL_CMPL_WRITE_ENABLE 149 writel(IOAT_DCACTRL_CMPL_WRITE_ENABLE
142 | IOAT_DMA_DCA_ANY_CPU, 150 | IOAT_DMA_DCA_ANY_CPU,
@@ -175,7 +183,7 @@ static void ioat1_dma_memcpy_issue_pending(struct dma_chan *chan)
175{ 183{
176 struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan); 184 struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
177 185
178 if (ioat_chan->pending != 0) { 186 if (ioat_chan->pending > 0) {
179 spin_lock_bh(&ioat_chan->desc_lock); 187 spin_lock_bh(&ioat_chan->desc_lock);
180 __ioat1_dma_memcpy_issue_pending(ioat_chan); 188 __ioat1_dma_memcpy_issue_pending(ioat_chan);
181 spin_unlock_bh(&ioat_chan->desc_lock); 189 spin_unlock_bh(&ioat_chan->desc_lock);
@@ -194,13 +202,228 @@ static void ioat2_dma_memcpy_issue_pending(struct dma_chan *chan)
194{ 202{
195 struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan); 203 struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
196 204
197 if (ioat_chan->pending != 0) { 205 if (ioat_chan->pending > 0) {
198 spin_lock_bh(&ioat_chan->desc_lock); 206 spin_lock_bh(&ioat_chan->desc_lock);
199 __ioat2_dma_memcpy_issue_pending(ioat_chan); 207 __ioat2_dma_memcpy_issue_pending(ioat_chan);
200 spin_unlock_bh(&ioat_chan->desc_lock); 208 spin_unlock_bh(&ioat_chan->desc_lock);
201 } 209 }
202} 210}
203 211
212
213/**
214 * ioat_dma_chan_reset_part2 - reinit the channel after a reset
215 */
216static void ioat_dma_chan_reset_part2(struct work_struct *work)
217{
218 struct ioat_dma_chan *ioat_chan =
219 container_of(work, struct ioat_dma_chan, work.work);
220 struct ioat_desc_sw *desc;
221
222 spin_lock_bh(&ioat_chan->cleanup_lock);
223 spin_lock_bh(&ioat_chan->desc_lock);
224
225 ioat_chan->completion_virt->low = 0;
226 ioat_chan->completion_virt->high = 0;
227 ioat_chan->pending = 0;
228
229 /*
230 * count the descriptors waiting, and be sure to do it
231 * right for both the CB1 line and the CB2 ring
232 */
233 ioat_chan->dmacount = 0;
234 if (ioat_chan->used_desc.prev) {
235 desc = to_ioat_desc(ioat_chan->used_desc.prev);
236 do {
237 ioat_chan->dmacount++;
238 desc = to_ioat_desc(desc->node.next);
239 } while (&desc->node != ioat_chan->used_desc.next);
240 }
241
242 /*
243 * write the new starting descriptor address
244 * this puts channel engine into ARMED state
245 */
246 desc = to_ioat_desc(ioat_chan->used_desc.prev);
247 switch (ioat_chan->device->version) {
248 case IOAT_VER_1_2:
249 writel(((u64) desc->async_tx.phys) & 0x00000000FFFFFFFF,
250 ioat_chan->reg_base + IOAT1_CHAINADDR_OFFSET_LOW);
251 writel(((u64) desc->async_tx.phys) >> 32,
252 ioat_chan->reg_base + IOAT1_CHAINADDR_OFFSET_HIGH);
253
254 writeb(IOAT_CHANCMD_START, ioat_chan->reg_base
255 + IOAT_CHANCMD_OFFSET(ioat_chan->device->version));
256 break;
257 case IOAT_VER_2_0:
258 writel(((u64) desc->async_tx.phys) & 0x00000000FFFFFFFF,
259 ioat_chan->reg_base + IOAT2_CHAINADDR_OFFSET_LOW);
260 writel(((u64) desc->async_tx.phys) >> 32,
261 ioat_chan->reg_base + IOAT2_CHAINADDR_OFFSET_HIGH);
262
263 /* tell the engine to go with what's left to be done */
264 writew(ioat_chan->dmacount,
265 ioat_chan->reg_base + IOAT_CHAN_DMACOUNT_OFFSET);
266
267 break;
268 }
269 dev_err(&ioat_chan->device->pdev->dev,
270 "chan%d reset - %d descs waiting, %d total desc\n",
271 chan_num(ioat_chan), ioat_chan->dmacount, ioat_chan->desccount);
272
273 spin_unlock_bh(&ioat_chan->desc_lock);
274 spin_unlock_bh(&ioat_chan->cleanup_lock);
275}
276
277/**
278 * ioat_dma_reset_channel - restart a channel
279 * @ioat_chan: IOAT DMA channel handle
280 */
281static void ioat_dma_reset_channel(struct ioat_dma_chan *ioat_chan)
282{
283 u32 chansts, chanerr;
284
285 if (!ioat_chan->used_desc.prev)
286 return;
287
288 chanerr = readl(ioat_chan->reg_base + IOAT_CHANERR_OFFSET);
289 chansts = (ioat_chan->completion_virt->low
290 & IOAT_CHANSTS_DMA_TRANSFER_STATUS);
291 if (chanerr) {
292 dev_err(&ioat_chan->device->pdev->dev,
293 "chan%d, CHANSTS = 0x%08x CHANERR = 0x%04x, clearing\n",
294 chan_num(ioat_chan), chansts, chanerr);
295 writel(chanerr, ioat_chan->reg_base + IOAT_CHANERR_OFFSET);
296 }
297
298 /*
299 * whack it upside the head with a reset
300 * and wait for things to settle out.
301 * force the pending count to a really big negative
302 * to make sure no one forces an issue_pending
303 * while we're waiting.
304 */
305
306 spin_lock_bh(&ioat_chan->desc_lock);
307 ioat_chan->pending = INT_MIN;
308 writeb(IOAT_CHANCMD_RESET,
309 ioat_chan->reg_base
310 + IOAT_CHANCMD_OFFSET(ioat_chan->device->version));
311 spin_unlock_bh(&ioat_chan->desc_lock);
312
313 /* schedule the 2nd half instead of sleeping a long time */
314 schedule_delayed_work(&ioat_chan->work, RESET_DELAY);
315}
316
317/**
318 * ioat_dma_chan_watchdog - watch for stuck channels
319 */
320static void ioat_dma_chan_watchdog(struct work_struct *work)
321{
322 struct ioatdma_device *device =
323 container_of(work, struct ioatdma_device, work.work);
324 struct ioat_dma_chan *ioat_chan;
325 int i;
326
327 union {
328 u64 full;
329 struct {
330 u32 low;
331 u32 high;