diff options
author | Dan Williams <dan.j.williams@intel.com> | 2009-01-06 13:38:20 -0500 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2009-01-06 13:38:20 -0500 |
commit | 4fac7fa57cf8001be259688468c825f836daf739 (patch) | |
tree | e59ab78a86f0599416b6255569d41d2ecc0d5512 | |
parent | 630738b9a52bee40cba685f4ff43fbbc28f2e1ff (diff) |
ioat: do not perform removal actions at shutdown
Unregistering services should only happen at "remove" time. This prevents
the device from being unregistered while dmaengine clients are still
active. Also, the comment on ioat_remove is stale since removal is prevented
while a channel may be in use.
Reported-by: Alexander Beregalov <a.beregalov@gmail.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r-- | drivers/dma/ioat.c | 92 |
1 files changed, 34 insertions, 58 deletions
diff --git a/drivers/dma/ioat.c b/drivers/dma/ioat.c index 9b16a3af9a0a..4105d6575b64 100644 --- a/drivers/dma/ioat.c +++ b/drivers/dma/ioat.c | |||
@@ -75,60 +75,10 @@ static int ioat_dca_enabled = 1; | |||
75 | module_param(ioat_dca_enabled, int, 0644); | 75 | module_param(ioat_dca_enabled, int, 0644); |
76 | MODULE_PARM_DESC(ioat_dca_enabled, "control support of dca service (default: 1)"); | 76 | MODULE_PARM_DESC(ioat_dca_enabled, "control support of dca service (default: 1)"); |
77 | 77 | ||
78 | static int ioat_setup_functionality(struct pci_dev *pdev, void __iomem *iobase) | ||
79 | { | ||
80 | struct ioat_device *device = pci_get_drvdata(pdev); | ||
81 | u8 version; | ||
82 | int err = 0; | ||
83 | |||
84 | version = readb(iobase + IOAT_VER_OFFSET); | ||
85 | switch (version) { | ||
86 | case IOAT_VER_1_2: | ||
87 | device->dma = ioat_dma_probe(pdev, iobase); | ||
88 | if (device->dma && ioat_dca_enabled) | ||
89 | device->dca = ioat_dca_init(pdev, iobase); | ||
90 | break; | ||
91 | case IOAT_VER_2_0: | ||
92 | device->dma = ioat_dma_probe(pdev, iobase); | ||
93 | if (device->dma && ioat_dca_enabled) | ||
94 | device->dca = ioat2_dca_init(pdev, iobase); | ||
95 | break; | ||
96 | case IOAT_VER_3_0: | ||
97 | device->dma = ioat_dma_probe(pdev, iobase); | ||
98 | if (device->dma && ioat_dca_enabled) | ||
99 | device->dca = ioat3_dca_init(pdev, iobase); | ||
100 | break; | ||
101 | default: | ||
102 | err = -ENODEV; | ||
103 | break; | ||
104 | } | ||
105 | if (!device->dma) | ||
106 | err = -ENODEV; | ||
107 | return err; | ||
108 | } | ||
109 | |||
110 | static void ioat_shutdown_functionality(struct pci_dev *pdev) | ||
111 | { | ||
112 | struct ioat_device *device = pci_get_drvdata(pdev); | ||
113 | |||
114 | dev_err(&pdev->dev, "Removing dma and dca services\n"); | ||
115 | if (device->dca) { | ||
116 | unregister_dca_provider(device->dca); | ||
117 | free_dca_provider(device->dca); | ||
118 | device->dca = NULL; | ||
119 | } | ||
120 | |||
121 | if (device->dma) { | ||
122 | ioat_dma_remove(device->dma); | ||
123 | device->dma = NULL; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | static struct pci_driver ioat_pci_driver = { | 78 | static struct pci_driver ioat_pci_driver = { |
128 | .name = "ioatdma", | 79 | .name = "ioatdma", |
129 | .id_table = ioat_pci_tbl, | 80 | .id_table = ioat_pci_tbl, |
130 | .probe = ioat_probe, | 81 | .probe = ioat_probe, |
131 | .shutdown = ioat_shutdown_functionality, | ||
132 | .remove = __devexit_p(ioat_remove), | 82 | .remove = __devexit_p(ioat_remove), |
133 | }; | 83 | }; |
134 | 84 | ||
@@ -179,7 +129,29 @@ static int __devinit ioat_probe(struct pci_dev *pdev, | |||
179 | 129 | ||
180 | pci_set_master(pdev); | 130 | pci_set_master(pdev); |
181 | 131 | ||
182 | err = ioat_setup_functionality(pdev, iobase); | 132 | switch (readb(iobase + IOAT_VER_OFFSET)) { |
133 | case IOAT_VER_1_2: | ||
134 | device->dma = ioat_dma_probe(pdev, iobase); | ||
135 | if (device->dma && ioat_dca_enabled) | ||
136 | device->dca = ioat_dca_init(pdev, iobase); | ||
137 | break; | ||
138 | case IOAT_VER_2_0: | ||
139 | device->dma = ioat_dma_probe(pdev, iobase); | ||
140 | if (device->dma && ioat_dca_enabled) | ||
141 | device->dca = ioat2_dca_init(pdev, iobase); | ||
142 | break; | ||
143 | case IOAT_VER_3_0: | ||
144 | device->dma = ioat_dma_probe(pdev, iobase); | ||
145 | if (device->dma && ioat_dca_enabled) | ||
146 | device->dca = ioat3_dca_init(pdev, iobase); | ||
147 | break; | ||
148 | default: | ||
149 | err = -ENODEV; | ||
150 | break; | ||
151 | } | ||
152 | if (!device->dma) | ||
153 | err = -ENODEV; | ||
154 | |||
183 | if (err) | 155 | if (err) |
184 | goto err_version; | 156 | goto err_version; |
185 | 157 | ||
@@ -198,17 +170,21 @@ err_enable_device: | |||
198 | return err; | 170 | return err; |
199 | } | 171 | } |
200 | 172 | ||
201 | /* | ||
202 | * It is unsafe to remove this module: if removed while a requested | ||
203 | * dma is outstanding, esp. from tcp, it is possible to hang while | ||
204 | * waiting for something that will never finish. However, if you're | ||
205 | * feeling lucky, this usually works just fine. | ||
206 | */ | ||
207 | static void __devexit ioat_remove(struct pci_dev *pdev) | 173 | static void __devexit ioat_remove(struct pci_dev *pdev) |
208 | { | 174 | { |
209 | struct ioat_device *device = pci_get_drvdata(pdev); | 175 | struct ioat_device *device = pci_get_drvdata(pdev); |
210 | 176 | ||
211 | ioat_shutdown_functionality(pdev); | 177 | dev_err(&pdev->dev, "Removing dma and dca services\n"); |
178 | if (device->dca) { | ||
179 | unregister_dca_provider(device->dca); | ||
180 | free_dca_provider(device->dca); | ||
181 | device->dca = NULL; | ||
182 | } | ||
183 | |||
184 | if (device->dma) { | ||
185 | ioat_dma_remove(device->dma); | ||
186 | device->dma = NULL; | ||
187 | } | ||
212 | 188 | ||
213 | kfree(device); | 189 | kfree(device); |
214 | } | 190 | } |