diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 322ee29..5560e39 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -316,8 +316,8 @@ EXPORT_SYMBOL(dma_async_client_chan_request); int dma_async_device_register(struct dma_device *device) { static int id; - int chancnt = 0; - struct dma_chan* chan; + int chancnt, err; + struct dma_chan *chan, *last; if (!device) return -ENODEV; @@ -326,9 +326,13 @@ int dma_async_device_register(struct dma_device *device) kref_init(&device->refcount); device->dev_id = id++; + err = chancnt = 0; + /* represent channels in sysfs. Probably want devs too */ list_for_each_entry(chan, &device->channels, device_node) { chan->local = alloc_percpu(typeof(*chan->local)); + + /* Should this be handled less relaxed? */ if (chan->local == NULL) continue; @@ -339,7 +343,11 @@ int dma_async_device_register(struct dma_device *device) device->dev_id, chan->chan_id); kref_get(&device->refcount); - class_device_register(&chan->class_dev); + err = class_device_register(&chan->class_dev); + if (err) { + last = chan; + goto err_dev_reg; + } } mutex_lock(&dma_list_mutex); @@ -349,6 +357,22 @@ int dma_async_device_register(struct dma_device *device) dma_chans_rebalance(); return 0; + +err_dev_reg: + list_for_each_entry(chan, &device->channels, device_node) { + kref_put(&device->refcount, dma_async_device_cleanup); + + if (chan->local) + free_percpu(chan->local); + + if (chan == last) + break; + + class_device_unregister(&chan->class_dev); + } + wait_for_completion(&device->done); + device->dev_id = 0; + return err; } EXPORT_SYMBOL(dma_async_device_register); diff --git a/drivers/dma/ioatdma.c b/drivers/dma/ioatdma.c index 8e87261..c25f548 100644 --- a/drivers/dma/ioatdma.c +++ b/drivers/dma/ioatdma.c @@ -768,10 +768,13 @@ static int __devinit ioat_probe(struct pci_dev *pdev, if (err) goto err_self_test; - dma_async_device_register(&device->common); + err = dma_async_device_register(&device->common) + if (err) + goto err_dev_reg; return 0; +err_dev_reg: err_self_test: err_irq: pci_pool_destroy(device->completion_pool);