diff options
author | Shannon Nelson <shannon.nelson@intel.com> | 2007-11-14 19:59:51 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-11-14 21:45:41 -0500 |
commit | 7bb67c14fd3778504fb77da30ce11582336dfced (patch) | |
tree | 24b65f267a98716824c7955be02af8879cfda688 /drivers/dma/ioat_dca.c | |
parent | cc9f2f8f68efcc73d8793a4df2c4c50196e90080 (diff) |
I/OAT: Add support for version 2 of ioatdma device
Add support for version 2 of the ioatdma device. This device handles
the descriptor chain and DCA services slightly differently:
- Instead of moving the dma descriptors between a busy and an idle chain,
this new version uses a single circular chain so that we don't have
rewrite the next_descriptor pointers as we add new requests, and the
device doesn't need to re-read the last descriptor.
- The new device has the DCA tags defined internally instead of needing
them defined statically.
Signed-off-by: Shannon Nelson <shannon.nelson@intel.com>
Cc: "Williams, Dan J" <dan.j.williams@intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/dma/ioat_dca.c')
-rw-r--r-- | drivers/dma/ioat_dca.c | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/drivers/dma/ioat_dca.c b/drivers/dma/ioat_dca.c index ba985715b803..0fa8a98051a8 100644 --- a/drivers/dma/ioat_dca.c +++ b/drivers/dma/ioat_dca.c | |||
@@ -261,3 +261,167 @@ struct dca_provider *ioat_dca_init(struct pci_dev *pdev, void __iomem *iobase) | |||
261 | return dca; | 261 | return dca; |
262 | } | 262 | } |
263 | 263 | ||
264 | |||
265 | static int ioat2_dca_add_requester(struct dca_provider *dca, struct device *dev) | ||
266 | { | ||
267 | struct ioat_dca_priv *ioatdca = dca_priv(dca); | ||
268 | struct pci_dev *pdev; | ||
269 | int i; | ||
270 | u16 id; | ||
271 | u16 global_req_table; | ||
272 | |||
273 | /* This implementation only supports PCI-Express */ | ||
274 | if (dev->bus != &pci_bus_type) | ||
275 | return -ENODEV; | ||
276 | pdev = to_pci_dev(dev); | ||
277 | id = dcaid_from_pcidev(pdev); | ||
278 | |||
279 | if (ioatdca->requester_count == ioatdca->max_requesters) | ||
280 | return -ENODEV; | ||
281 | |||
282 | for (i = 0; i < ioatdca->max_requesters; i++) { | ||
283 | if (ioatdca->req_slots[i].pdev == NULL) { | ||
284 | /* found an empty slot */ | ||
285 | ioatdca->requester_count++; | ||
286 | ioatdca->req_slots[i].pdev = pdev; | ||
287 | ioatdca->req_slots[i].rid = id; | ||
288 | global_req_table = | ||
289 | readw(ioatdca->dca_base + IOAT_DCA_GREQID_OFFSET); | ||
290 | writel(id | IOAT_DCA_GREQID_VALID, | ||
291 | ioatdca->iobase + global_req_table + (i * 4)); | ||
292 | return i; | ||
293 | } | ||
294 | } | ||
295 | /* Error, ioatdma->requester_count is out of whack */ | ||
296 | return -EFAULT; | ||
297 | } | ||
298 | |||
299 | static int ioat2_dca_remove_requester(struct dca_provider *dca, | ||
300 | struct device *dev) | ||
301 | { | ||
302 | struct ioat_dca_priv *ioatdca = dca_priv(dca); | ||
303 | struct pci_dev *pdev; | ||
304 | int i; | ||
305 | u16 global_req_table; | ||
306 | |||
307 | /* This implementation only supports PCI-Express */ | ||
308 | if (dev->bus != &pci_bus_type) | ||
309 | return -ENODEV; | ||
310 | pdev = to_pci_dev(dev); | ||
311 | |||
312 | for (i = 0; i < ioatdca->max_requesters; i++) { | ||
313 | if (ioatdca->req_slots[i].pdev == pdev) { | ||
314 | global_req_table = | ||
315 | readw(ioatdca->dca_base + IOAT_DCA_GREQID_OFFSET); | ||
316 | writel(0, ioatdca->iobase + global_req_table + (i * 4)); | ||
317 | ioatdca->req_slots[i].pdev = NULL; | ||
318 | ioatdca->req_slots[i].rid = 0; | ||
319 | ioatdca->requester_count--; | ||
320 | return i; | ||
321 | } | ||
322 | } | ||
323 | return -ENODEV; | ||
324 | } | ||
325 | |||
326 | static u8 ioat2_dca_get_tag(struct dca_provider *dca, int cpu) | ||
327 | { | ||
328 | u8 tag; | ||
329 | |||
330 | tag = ioat_dca_get_tag(dca, cpu); | ||
331 | tag = (~tag) & 0x1F; | ||
332 | return tag; | ||
333 | } | ||
334 | |||
335 | static struct dca_ops ioat2_dca_ops = { | ||
336 | .add_requester = ioat2_dca_add_requester, | ||
337 | .remove_requester = ioat2_dca_remove_requester, | ||
338 | .get_tag = ioat2_dca_get_tag, | ||
339 | }; | ||
340 | |||
341 | static int ioat2_dca_count_dca_slots(void *iobase, u16 dca_offset) | ||
342 | { | ||
343 | int slots = 0; | ||
344 | u32 req; | ||
345 | u16 global_req_table; | ||
346 | |||
347 | global_req_table = readw(iobase + dca_offset + IOAT_DCA_GREQID_OFFSET); | ||
348 | if (global_req_table == 0) | ||
349 | return 0; | ||
350 | do { | ||
351 | req = readl(iobase + global_req_table + (slots * sizeof(u32))); | ||
352 | slots++; | ||
353 | } while ((req & IOAT_DCA_GREQID_LASTID) == 0); | ||
354 | |||
355 | return slots; | ||
356 | } | ||
357 | |||
358 | struct dca_provider *ioat2_dca_init(struct pci_dev *pdev, void __iomem *iobase) | ||
359 | { | ||
360 | struct dca_provider *dca; | ||
361 | struct ioat_dca_priv *ioatdca; | ||
362 | int slots; | ||
363 | int i; | ||
364 | int err; | ||
365 | u32 tag_map; | ||
366 | u16 dca_offset; | ||
367 | u16 csi_fsb_control; | ||
368 | u16 pcie_control; | ||
369 | u8 bit; | ||
370 | |||
371 | if (!system_has_dca_enabled(pdev)) | ||
372 | return NULL; | ||
373 | |||
374 | dca_offset = readw(iobase + IOAT_DCAOFFSET_OFFSET); | ||
375 | if (dca_offset == 0) | ||
376 | return NULL; | ||
377 | |||
378 | slots = ioat2_dca_count_dca_slots(iobase, dca_offset); | ||
379 | if (slots == 0) | ||
380 | return NULL; | ||
381 | |||
382 | dca = alloc_dca_provider(&ioat2_dca_ops, | ||
383 | sizeof(*ioatdca) | ||
384 | + (sizeof(struct ioat_dca_slot) * slots)); | ||
385 | if (!dca) | ||
386 | return NULL; | ||
387 | |||
388 | ioatdca = dca_priv(dca); | ||
389 | ioatdca->iobase = iobase; | ||
390 | ioatdca->dca_base = iobase + dca_offset; | ||
391 | ioatdca->max_requesters = slots; | ||
392 | |||
393 | /* some bios might not know to turn these on */ | ||
394 | csi_fsb_control = readw(ioatdca->dca_base + IOAT_FSB_CAP_ENABLE_OFFSET); | ||
395 | if ((csi_fsb_control & IOAT_FSB_CAP_ENABLE_PREFETCH) == 0) { | ||
396 | csi_fsb_control |= IOAT_FSB_CAP_ENABLE_PREFETCH; | ||
397 | writew(csi_fsb_control, | ||
398 | ioatdca->dca_base + IOAT_FSB_CAP_ENABLE_OFFSET); | ||
399 | } | ||
400 | pcie_control = readw(ioatdca->dca_base + IOAT_PCI_CAP_ENABLE_OFFSET); | ||
401 | if ((pcie_control & IOAT_PCI_CAP_ENABLE_MEMWR) == 0) { | ||
402 | pcie_control |= IOAT_PCI_CAP_ENABLE_MEMWR; | ||
403 | writew(pcie_control, | ||
404 | ioatdca->dca_base + IOAT_PCI_CAP_ENABLE_OFFSET); | ||
405 | } | ||
406 | |||
407 | |||
408 | /* TODO version, compatibility and configuration checks */ | ||
409 | |||
410 | /* copy out the APIC to DCA tag map */ | ||
411 | tag_map = readl(ioatdca->dca_base + IOAT_APICID_TAG_MAP_OFFSET); | ||
412 | for (i = 0; i < 5; i++) { | ||
413 | bit = (tag_map >> (4 * i)) & 0x0f; | ||
414 | if (bit < 8) | ||
415 | ioatdca->tag_map[i] = bit | DCA_TAG_MAP_VALID; | ||
416 | else | ||
417 | ioatdca->tag_map[i] = 0; | ||
418 | } | ||
419 | |||
420 | err = register_dca_provider(dca, &pdev->dev); | ||
421 | if (err) { | ||
422 | free_dca_provider(dca); | ||
423 | return NULL; | ||
424 | } | ||
425 | |||
426 | return dca; | ||
427 | } | ||