diff options
author | Maciej Sosnowski <maciej.sosnowski@intel.com> | 2008-07-22 20:30:57 -0400 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2008-07-22 20:30:57 -0400 |
commit | 7f1b358a236ee9c19657a619ac6f2dcabcaa0924 (patch) | |
tree | 04eade38d4f8da94d7051f51875ed500b49b4756 /drivers/dma/ioat_dma.c | |
parent | 16a37acaaf4aaa631ba3f83710ed6cdb1a597520 (diff) |
I/OAT: I/OAT version 3.0 support
This patch adds to ioatdma and dca modules
support for Intel I/OAT DMA engine ver.3 (aka CB3 device).
The main features of I/OAT ver.3 are:
* 8 single channel DMA devices (8 channels total)
* 8 DCA providers, each can accept 2 requesters
* 8-bit TAG values and 32-bit extended APIC IDs
Signed-off-by: Maciej Sosnowski <maciej.sosnowski@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/dma/ioat_dma.c')
-rw-r--r-- | drivers/dma/ioat_dma.c | 96 |
1 files changed, 85 insertions, 11 deletions
diff --git a/drivers/dma/ioat_dma.c b/drivers/dma/ioat_dma.c index ece5a0e3a335..a52156e56886 100644 --- a/drivers/dma/ioat_dma.c +++ b/drivers/dma/ioat_dma.c | |||
@@ -53,6 +53,12 @@ MODULE_PARM_DESC(ioat_pending_level, | |||
53 | static void ioat_dma_chan_reset_part2(struct work_struct *work); | 53 | static void ioat_dma_chan_reset_part2(struct work_struct *work); |
54 | static void ioat_dma_chan_watchdog(struct work_struct *work); | 54 | static void ioat_dma_chan_watchdog(struct work_struct *work); |
55 | 55 | ||
56 | /* | ||
57 | * workaround for IOAT ver.3.0 null descriptor issue | ||
58 | * (channel returns error when size is 0) | ||
59 | */ | ||
60 | #define NULL_DESC_BUFFER_SIZE 1 | ||
61 | |||
56 | /* internal functions */ | 62 | /* internal functions */ |
57 | static void ioat_dma_start_null_desc(struct ioat_dma_chan *ioat_chan); | 63 | static void ioat_dma_start_null_desc(struct ioat_dma_chan *ioat_chan); |
58 | static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan); | 64 | static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan); |
@@ -129,6 +135,38 @@ static int ioat_dma_enumerate_channels(struct ioatdma_device *device) | |||
129 | int i; | 135 | int i; |
130 | struct ioat_dma_chan *ioat_chan; | 136 | struct ioat_dma_chan *ioat_chan; |
131 | 137 | ||
138 | /* | ||
139 | * IOAT ver.3 workarounds | ||
140 | */ | ||
141 | if (device->version == IOAT_VER_3_0) { | ||
142 | u32 chan_err_mask; | ||
143 | u16 dev_id; | ||
144 | u32 dmauncerrsts; | ||
145 | |||
146 | /* | ||
147 | * Write CHANERRMSK_INT with 3E07h to mask out the errors | ||
148 | * that can cause stability issues for IOAT ver.3 | ||
149 | */ | ||
150 | chan_err_mask = 0x3E07; | ||
151 | pci_write_config_dword(device->pdev, | ||
152 | IOAT_PCI_CHANERRMASK_INT_OFFSET, | ||
153 | chan_err_mask); | ||
154 | |||
155 | /* | ||
156 | * Clear DMAUNCERRSTS Cfg-Reg Parity Error status bit | ||
157 | * (workaround for spurious config parity error after restart) | ||
158 | */ | ||
159 | pci_read_config_word(device->pdev, | ||
160 | IOAT_PCI_DEVICE_ID_OFFSET, | ||
161 | &dev_id); | ||
162 | if (dev_id == PCI_DEVICE_ID_INTEL_IOAT_TBG0) { | ||
163 | dmauncerrsts = 0x10; | ||
164 | pci_write_config_dword(device->pdev, | ||
165 | IOAT_PCI_DMAUNCERRSTS_OFFSET, | ||
166 | dmauncerrsts); | ||
167 | } | ||
168 | } | ||
169 | |||
132 | device->common.chancnt = readb(device->reg_base + IOAT_CHANCNT_OFFSET); | 170 | device->common.chancnt = readb(device->reg_base + IOAT_CHANCNT_OFFSET); |
133 | xfercap_scale = readb(device->reg_base + IOAT_XFERCAP_OFFSET); | 171 | xfercap_scale = readb(device->reg_base + IOAT_XFERCAP_OFFSET); |
134 | xfercap = (xfercap_scale == 0 ? -1 : (1UL << xfercap_scale)); | 172 | xfercap = (xfercap_scale == 0 ? -1 : (1UL << xfercap_scale)); |
@@ -473,6 +511,13 @@ static dma_cookie_t ioat1_tx_submit(struct dma_async_tx_descriptor *tx) | |||
473 | prev = new; | 511 | prev = new; |
474 | } while (len && (new = ioat1_dma_get_next_descriptor(ioat_chan))); | 512 | } while (len && (new = ioat1_dma_get_next_descriptor(ioat_chan))); |
475 | 513 | ||
514 | if (!new) { | ||
515 | dev_err(&ioat_chan->device->pdev->dev, | ||
516 | "tx submit failed\n"); | ||
517 | spin_unlock_bh(&ioat_chan->desc_lock); | ||
518 | return -ENOMEM; | ||
519 | } | ||
520 | |||
476 | hw->ctl = IOAT_DMA_DESCRIPTOR_CTL_CP_STS; | 521 | hw->ctl = IOAT_DMA_DESCRIPTOR_CTL_CP_STS; |
477 | if (new->async_tx.callback) { | 522 | if (new->async_tx.callback) { |
478 | hw->ctl |= IOAT_DMA_DESCRIPTOR_CTL_INT_GN; | 523 | hw->ctl |= IOAT_DMA_DESCRIPTOR_CTL_INT_GN; |
@@ -558,7 +603,14 @@ static dma_cookie_t ioat2_tx_submit(struct dma_async_tx_descriptor *tx) | |||
558 | desc_count++; | 603 | desc_count++; |
559 | } while (len && (new = ioat2_dma_get_next_descriptor(ioat_chan))); | 604 | } while (len && (new = ioat2_dma_get_next_descriptor(ioat_chan))); |
560 | 605 | ||
561 | hw->ctl = IOAT_DMA_DESCRIPTOR_CTL_CP_STS; | 606 | if (!new) { |
607 | dev_err(&ioat_chan->device->pdev->dev, | ||
608 | "tx submit failed\n"); | ||
609 | spin_unlock_bh(&ioat_chan->desc_lock); | ||
610 | return -ENOMEM; | ||
611 | } | ||
612 | |||
613 | hw->ctl |= IOAT_DMA_DESCRIPTOR_CTL_CP_STS; | ||
562 | if (new->async_tx.callback) { | 614 | if (new->async_tx.callback) { |
563 | hw->ctl |= IOAT_DMA_DESCRIPTOR_CTL_INT_GN; | 615 | hw->ctl |= IOAT_DMA_DESCRIPTOR_CTL_INT_GN; |
564 | if (first != new) { | 616 | if (first != new) { |
@@ -629,6 +681,7 @@ static struct ioat_desc_sw *ioat_dma_alloc_descriptor( | |||
629 | desc_sw->async_tx.tx_submit = ioat1_tx_submit; | 681 | desc_sw->async_tx.tx_submit = ioat1_tx_submit; |
630 | break; | 682 | break; |
631 | case IOAT_VER_2_0: | 683 | case IOAT_VER_2_0: |
684 | case IOAT_VER_3_0: | ||
632 | desc_sw->async_tx.tx_submit = ioat2_tx_submit; | 685 | desc_sw->async_tx.tx_submit = ioat2_tx_submit; |
633 | break; | 686 | break; |
634 | } | 687 | } |
@@ -779,6 +832,7 @@ static void ioat_dma_free_chan_resources(struct dma_chan *chan) | |||
779 | } | 832 | } |
780 | break; | 833 | break; |
781 | case IOAT_VER_2_0: | 834 | case IOAT_VER_2_0: |
835 | case IOAT_VER_3_0: | ||
782 | list_for_each_entry_safe(desc, _desc, | 836 | list_for_each_entry_safe(desc, _desc, |
783 | ioat_chan->free_desc.next, node) { | 837 | ioat_chan->free_desc.next, node) { |
784 | list_del(&desc->node); | 838 | list_del(&desc->node); |
@@ -868,7 +922,8 @@ ioat2_dma_get_next_descriptor(struct ioat_dma_chan *ioat_chan) | |||
868 | 922 | ||
869 | /* set up the noop descriptor */ | 923 | /* set up the noop descriptor */ |
870 | noop_desc = to_ioat_desc(ioat_chan->used_desc.next); | 924 | noop_desc = to_ioat_desc(ioat_chan->used_desc.next); |
871 | noop_desc->hw->size = 0; | 925 | /* set size to non-zero value (channel returns error when size is 0) */ |
926 | noop_desc->hw->size = NULL_DESC_BUFFER_SIZE; | ||
872 | noop_desc->hw->ctl = IOAT_DMA_DESCRIPTOR_NUL; | 927 | noop_desc->hw->ctl = IOAT_DMA_DESCRIPTOR_NUL; |
873 | noop_desc->hw->src_addr = 0; | 928 | noop_desc->hw->src_addr = 0; |
874 | noop_desc->hw->dst_addr = 0; | 929 | noop_desc->hw->dst_addr = 0; |
@@ -918,6 +973,7 @@ static struct ioat_desc_sw *ioat_dma_get_next_descriptor( | |||
918 | return ioat1_dma_get_next_descriptor(ioat_chan); | 973 | return ioat1_dma_get_next_descriptor(ioat_chan); |
919 | break; | 974 | break; |
920 | case IOAT_VER_2_0: | 975 | case IOAT_VER_2_0: |
976 | case IOAT_VER_3_0: | ||
921 | return ioat2_dma_get_next_descriptor(ioat_chan); | 977 | return ioat2_dma_get_next_descriptor(ioat_chan); |
922 | break; | 978 | break; |
923 | } | 979 | } |
@@ -1061,10 +1117,12 @@ static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan) | |||
1061 | * perhaps we're stuck so hard that the watchdog can't go off? | 1117 | * perhaps we're stuck so hard that the watchdog can't go off? |
1062 | * try to catch it after 2 seconds | 1118 | * try to catch it after 2 seconds |
1063 | */ | 1119 | */ |
1064 | if (time_after(jiffies, | 1120 | if (ioat_chan->device->version != IOAT_VER_3_0) { |
1065 | ioat_chan->last_completion_time + HZ*WATCHDOG_DELAY)) { | 1121 | if (time_after(jiffies, |
1066 | ioat_dma_chan_watchdog(&(ioat_chan->device->work.work)); | 1122 | ioat_chan->last_completion_time + HZ*WATCHDOG_DELAY)) { |
1067 | ioat_chan->last_completion_time = jiffies; | 1123 | ioat_dma_chan_watchdog(&(ioat_chan->device->work.work)); |
1124 | ioat_chan->last_completion_time = jiffies; | ||
1125 | } | ||
1068 | } | 1126 | } |
1069 | return; | 1127 | return; |
1070 | } | 1128 | } |
@@ -1120,6 +1178,7 @@ static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan) | |||
1120 | } | 1178 | } |
1121 | break; | 1179 | break; |
1122 | case IOAT_VER_2_0: | 1180 | case IOAT_VER_2_0: |
1181 | case IOAT_VER_3_0: | ||
1123 | /* has some other thread has already cleaned up? */ | 1182 | /* has some other thread has already cleaned up? */ |
1124 | if (ioat_chan->used_desc.prev == NULL) | 1183 | if (ioat_chan->used_desc.prev == NULL) |
1125 | break; | 1184 | break; |
@@ -1223,10 +1282,19 @@ static void ioat_dma_start_null_desc(struct ioat_dma_chan *ioat_chan) | |||
1223 | spin_lock_bh(&ioat_chan->desc_lock); | 1282 | spin_lock_bh(&ioat_chan->desc_lock); |
1224 | 1283 | ||
1225 | desc = ioat_dma_get_next_descriptor(ioat_chan); | 1284 | desc = ioat_dma_get_next_descriptor(ioat_chan); |
1285 | |||
1286 | if (!desc) { | ||
1287 | dev_err(&ioat_chan->device->pdev->dev, | ||
1288 | "Unable to start null desc - get next desc failed\n"); | ||
1289 | spin_unlock_bh(&ioat_chan->desc_lock); | ||
1290 | return; | ||
1291 | } | ||
1292 | |||
1226 | desc->hw->ctl = IOAT_DMA_DESCRIPTOR_NUL | 1293 | desc->hw->ctl = IOAT_DMA_DESCRIPTOR_NUL |
1227 | | IOAT_DMA_DESCRIPTOR_CTL_INT_GN | 1294 | | IOAT_DMA_DESCRIPTOR_CTL_INT_GN |
1228 | | IOAT_DMA_DESCRIPTOR_CTL_CP_STS; | 1295 | | IOAT_DMA_DESCRIPTOR_CTL_CP_STS; |
1229 | desc->hw->size = 0; | 1296 | /* set size to non-zero value (channel returns error when size is 0) */ |
1297 | desc->hw->size = NULL_DESC_BUFFER_SIZE; | ||
1230 | desc->hw->src_addr = 0; | 1298 | desc->hw->src_addr = 0; |
1231 | desc->hw->dst_addr = 0; | 1299 | desc->hw->dst_addr = 0; |
1232 | async_tx_ack(&desc->async_tx); | 1300 | async_tx_ack(&desc->async_tx); |
@@ -1244,6 +1312,7 @@ static void ioat_dma_start_null_desc(struct ioat_dma_chan *ioat_chan) | |||
1244 | + IOAT_CHANCMD_OFFSET(ioat_chan->device->version)); | 1312 | + IOAT_CHANCMD_OFFSET(ioat_chan->device->version)); |
1245 | break; | 1313 | break; |
1246 | case IOAT_VER_2_0: | 1314 | case IOAT_VER_2_0: |
1315 | case IOAT_VER_3_0: | ||
1247 | writel(((u64) desc->async_tx.phys) & 0x00000000FFFFFFFF, | 1316 | writel(((u64) desc->async_tx.phys) & 0x00000000FFFFFFFF, |
1248 | ioat_chan->reg_base + IOAT2_CHAINADDR_OFFSET_LOW); | 1317 | ioat_chan->reg_base + IOAT2_CHAINADDR_OFFSET_LOW); |
1249 | writel(((u64) desc->async_tx.phys) >> 32, | 1318 | writel(((u64) desc->async_tx.phys) >> 32, |
@@ -1562,6 +1631,7 @@ struct ioatdma_device *ioat_dma_probe(struct pci_dev *pdev, | |||
1562 | ioat1_dma_memcpy_issue_pending; | 1631 | ioat1_dma_memcpy_issue_pending; |
1563 | break; | 1632 | break; |
1564 | case IOAT_VER_2_0: | 1633 | case IOAT_VER_2_0: |
1634 | case IOAT_VER_3_0: | ||
1565 | device->common.device_prep_dma_memcpy = ioat2_dma_prep_memcpy; | 1635 | device->common.device_prep_dma_memcpy = ioat2_dma_prep_memcpy; |
1566 | device->common.device_issue_pending = | 1636 | device->common.device_issue_pending = |
1567 | ioat2_dma_memcpy_issue_pending; | 1637 | ioat2_dma_memcpy_issue_pending; |
@@ -1585,9 +1655,11 @@ struct ioatdma_device *ioat_dma_probe(struct pci_dev *pdev, | |||
1585 | 1655 | ||
1586 | dma_async_device_register(&device->common); | 1656 | dma_async_device_register(&device->common); |
1587 | 1657 | ||
1588 | INIT_DELAYED_WORK(&device->work, ioat_dma_chan_watchdog); | 1658 | if (device->version != IOAT_VER_3_0) { |
1589 | schedule_delayed_work(&device->work, | 1659 | INIT_DELAYED_WORK(&device->work, ioat_dma_chan_watchdog); |
1590 | WATCHDOG_DELAY); | 1660 | schedule_delayed_work(&device->work, |
1661 | WATCHDOG_DELAY); | ||
1662 | } | ||
1591 | 1663 | ||
1592 | return device; | 1664 | return device; |
1593 | 1665 | ||
@@ -1621,7 +1693,9 @@ void ioat_dma_remove(struct ioatdma_device *device) | |||
1621 | pci_release_regions(device->pdev); | 1693 | pci_release_regions(device->pdev); |
1622 | pci_disable_device(device->pdev); | 1694 | pci_disable_device(device->pdev); |
1623 | 1695 | ||
1624 | cancel_delayed_work(&device->work); | 1696 | if (device->version != IOAT_VER_3_0) { |
1697 | cancel_delayed_work(&device->work); | ||
1698 | } | ||
1625 | 1699 | ||
1626 | list_for_each_entry_safe(chan, _chan, | 1700 | list_for_each_entry_safe(chan, _chan, |
1627 | &device->common.channels, device_node) { | 1701 | &device->common.channels, device_node) { |