[alsa-devel] [PATCH RFC 0/5] Add devres support to card resources
Hi,
the devres or device-managed resource allocation is a popular method among many drivers but we didn't have such a mechanism for the core sound card objects. Here is an attempt to implement that.
The first patch gives the devm-version of page allocator helper, and the second patch provides the devm-version of snd_card_new(). The rest patches are examples of the new API usages.
As of now, this patch series is still an RFC. The usefulness of this is still unclear, but I believe this can be used in all legacy ALSA drivers pretty well. For ASoC, this would help very little, supposedly, though.
The latest patches are found in topic/devres branch of my sound.git tree, too.
thanks,
Takashi
===
Takashi Iwai (5): ALSA: core: Add device-managed page allocator helper ALSA: core: Add managed card creation ALSA: intel8x0: Allocate resources with device-managed APIs ALSA: atiixp: Allocate resources with device-managed APIs ALSA: hda: Allocate resources with device-managed APIs
include/sound/core.h | 5 ++ include/sound/memalloc.h | 4 + sound/core/init.c | 95 +++++++++++++++++++++- sound/core/memalloc.c | 88 +++++++++++++++----- sound/pci/atiixp.c | 104 +++++++----------------- sound/pci/atiixp_modem.c | 104 +++++++----------------- sound/pci/hda/hda_controller.h | 1 - sound/pci/hda/hda_intel.c | 43 +++------- sound/pci/intel8x0.c | 143 +++++++++++---------------------- sound/pci/intel8x0m.c | 143 +++++++++++---------------------- 10 files changed, 332 insertions(+), 398 deletions(-)
This is a preparation for managing the whole resource via devres. As a first step, add a new allocator function, snd_devm_alloc_pages() to manage the allocated pages via devres, so that the pages will be automagically released as device unbinding.
Unlike the old snd_dma_alloc_pages(), the new function returns directly the snd_dma_buffer pointer. The caller needs to check the error via IS_ERR().
Signed-off-by: Takashi Iwai tiwai@suse.de --- include/sound/memalloc.h | 4 ++ sound/core/memalloc.c | 88 ++++++++++++++++++++++++++++++++-------- 2 files changed, 74 insertions(+), 18 deletions(-)
diff --git a/include/sound/memalloc.h b/include/sound/memalloc.h index af3fa577fa06..3a1d9fb44fcf 100644 --- a/include/sound/memalloc.h +++ b/include/sound/memalloc.h @@ -156,5 +156,9 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab); void *snd_malloc_pages(size_t size, gfp_t gfp_flags); void snd_free_pages(void *ptr, size_t size);
+/* device-managed memory allocator */ +struct snd_dma_buffer *snd_devm_alloc_pages(struct device *dev, int type, + size_t size); + #endif /* __SOUND_MEMALLOC_H */
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index aa266907ec9b..a54d7aacec43 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -161,22 +161,8 @@ static void snd_free_dev_iram(struct snd_dma_buffer *dmab) * */
- -/** - * snd_dma_alloc_pages - allocate the buffer area according to the given type - * @type: the DMA buffer type - * @device: the device pointer - * @size: the buffer size to allocate - * @dmab: buffer allocation record to store the allocated data - * - * Calls the memory-allocator function for the corresponding - * buffer type. - * - * Return: Zero if the buffer with the given size is allocated successfully, - * otherwise a negative value on error. - */ -int snd_dma_alloc_pages(int type, struct device *device, size_t size, - struct snd_dma_buffer *dmab) +static int __snd_dma_alloc_pages(struct device *device, int type, size_t size, + gfp_t gfp_flags, struct snd_dma_buffer *dmab) { if (WARN_ON(!size)) return -ENXIO; @@ -188,8 +174,7 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, dmab->bytes = 0; switch (type) { case SNDRV_DMA_TYPE_CONTINUOUS: - dmab->area = snd_malloc_pages(size, - (__force gfp_t)(unsigned long)device); + dmab->area = snd_malloc_pages(size, gfp_flags); dmab->addr = 0; break; #ifdef CONFIG_HAS_DMA @@ -225,6 +210,30 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, dmab->bytes = size; return 0; } + +/** + * snd_dma_alloc_pages - allocate the buffer area according to the given type + * @type: the DMA buffer type + * @device: the device pointer + * @size: the buffer size to allocate + * @dmab: buffer allocation record to store the allocated data + * + * Calls the memory-allocator function for the corresponding + * buffer type. + * + * Return: Zero if the buffer with the given size is allocated successfully, + * otherwise a negative value on error. + */ +int snd_dma_alloc_pages(int type, struct device *device, size_t size, + struct snd_dma_buffer *dmab) +{ + gfp_t gfp_flags = 0; + + if (type == SNDRV_DMA_TYPE_CONTINUOUS) + gfp_flags = (__force gfp_t)(unsigned long)device; + + return __snd_dma_alloc_pages(device, type, size, gfp_flags, dmab); +} EXPORT_SYMBOL(snd_dma_alloc_pages);
/** @@ -296,3 +305,46 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab) } } EXPORT_SYMBOL(snd_dma_free_pages); + +/* called by devres */ +static void __snd_release_pages(struct device *dev, void *res) +{ + snd_dma_free_pages(res); +} + +/** + * snd_devm_alloc_pages - allocate the buffer and manage with devres + * @dev: the device pointer + * @type: the DMA buffer type + * @size: the buffer size to allocate + * + * Allocate buffer pages depending on the given type and manage using devres. + * The pages will be released automatically at the device removal. + * + * The function cannot handle GFP flags for SNDRV_DMA_TYPE_CONTINUOUS type, + * only GFP_KERNEL is assumed. + * + * The function returns the snd_dma_buffer object at success or the encoded + * error pointer via ERR_PTR(). The caller needs to check the error via + * IS_ERR() and PTR_ERR(). + */ +struct snd_dma_buffer * +snd_devm_alloc_pages(struct device *dev, int type, size_t size) +{ + struct snd_dma_buffer *dmab; + int err; + + dmab = devres_alloc(__snd_release_pages, sizeof(*dmab), GFP_KERNEL); + if (!dmab) + return ERR_PTR(-ENOMEM); + + err = __snd_dma_alloc_pages(dev, type, size, GFP_KERNEL, dmab); + if (err < 0) { + devres_free(dmab); + return ERR_PTR(err); + } + + devres_add(dev, dmab); + return dmab; +} +EXPORT_SYMBOL_GPL(snd_devm_alloc_pages);
Per popular demands, this patch adds a new ALSA core API function, snd_devm_card_new(), to create a snd_card object in a managed way via devres. When a card object is created by this new function, it's released automatically at the device release. It includes also the call of snd_card_free().
However, the story isn't that simple. A caveat is that We have to call snd_card_new(), more specifically, the disconnection part, at very first of the whole resource release procedure. This assures that the exposed devices are deleted and sync with the all accessing processes getting closed.
For achieving it, snd_card_register() adds a new devres action to trigger snd_card_free() automatically when the given card object is a "managed" one. Since usually snd_card_register() is the last step of the initialization, this should work in most cases.
With all these tricks, some drivers can get rid of the whole the driver remove callback.
About a bit of implementation details: the patch adds two new flags to snd_card object, managed and releasing. The former indicates that the object was created via snd_devm_card_new(), and the latter is used for avoiding the double-free of snd_card_free() calls. Both flags are fairly internal and likely uninteresting to normal users.
Signed-off-by: Takashi Iwai tiwai@suse.de --- include/sound/core.h | 5 +++ sound/core/init.c | 95 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 96 insertions(+), 4 deletions(-)
diff --git a/include/sound/core.h b/include/sound/core.h index 36a5934cf4b1..6ff75f92ec7d 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -133,6 +133,8 @@ struct snd_card { struct device card_dev; /* cardX object for sysfs */ const struct attribute_group *dev_groups[4]; /* assigned sysfs attr */ bool registered; /* card_dev is registered? */ + bool managed; /* managed via devres */ + bool releasing; /* during card free process */ wait_queue_head_t remove_sleep;
#ifdef CONFIG_PM @@ -239,6 +241,9 @@ extern int (*snd_mixer_oss_notify_callback)(struct snd_card *card, int cmd); int snd_card_new(struct device *parent, int idx, const char *xid, struct module *module, int extra_size, struct snd_card **card_ret); +int snd_devm_card_new(struct device *parent, int idx, const char *xid, + struct module *module, int extra_size, + struct snd_card **card_ret);
int snd_card_disconnect(struct snd_card *card); void snd_card_disconnect_sync(struct snd_card *card); diff --git a/sound/core/init.c b/sound/core/init.c index 4849c611c0fe..2eade57db4b4 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -173,6 +173,9 @@ void snd_device_initialize(struct device *dev, struct snd_card *card) } EXPORT_SYMBOL_GPL(snd_device_initialize);
+static int snd_card_init(struct snd_card *card, struct device *parent, + int idx, const char *xid, struct module *module, + int extra_size); static int snd_card_do_free(struct snd_card *card); static const struct attribute_group card_dev_attr_group;
@@ -214,6 +217,73 @@ int snd_card_new(struct device *parent, int idx, const char *xid, card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL); if (!card) return -ENOMEM; + + err = snd_card_init(card, parent, idx, xid, module, extra_size); + if (err < 0) { + kfree(card); + return err; + } + + *card_ret = card; + return 0; +} +EXPORT_SYMBOL(snd_card_new); + +static void __snd_card_release(struct device *dev, void *data) +{ + snd_card_free(data); +} + +/** + * snd_devm_card_new - managed snd_card object creation + * @parent: the parent device object + * @idx: card index (address) [0 ... (SNDRV_CARDS-1)] + * @xid: card identification (ASCII string) + * @module: top level module for locking + * @extra_size: allocate this extra size after the main soundcard structure + * @card_ret: the pointer to store the created card instance + * + * This function works like snd_card_new() but manages the allocated resource + * via devres, i.e. you don't need to free explicitly. + * + * When a snd_card object is created with this function and registered via + * snd_card_register(), the very first devres action to call snd_card_free() + * is added automatically. In that way, the resource disconnection is assured + * at first, then released in the expected order. + */ +int snd_devm_card_new(struct device *parent, int idx, const char *xid, + struct module *module, int extra_size, + struct snd_card **card_ret) +{ + struct snd_card *card; + int err; + + *card_ret = NULL; + if (extra_size < 0) + extra_size = 0; + card = devres_alloc(__snd_card_release, sizeof(*card) + extra_size, + GFP_KERNEL); + if (!card) + return -ENOMEM; + card->managed = true; + err = snd_card_init(card, parent, idx, xid, module, extra_size); + if (err < 0) { + devres_free(card); + return err; + } + + devres_add(parent, card); + *card_ret = card; + return 0; +} +EXPORT_SYMBOL_GPL(snd_devm_card_new); + +static int snd_card_init(struct snd_card *card, struct device *parent, + int idx, const char *xid, struct module *module, + int extra_size) +{ + int err; + if (extra_size > 0) card->private_data = (char *)card + sizeof(struct snd_card); if (xid) @@ -235,7 +305,6 @@ int snd_card_new(struct device *parent, int idx, const char *xid, mutex_unlock(&snd_card_mutex); dev_err(parent, "cannot find the slot for index %d (range 0-%i), error: %d\n", idx, snd_ecards_limit - 1, err); - kfree(card); return err; } set_bit(idx, snd_cards_lock); /* lock it */ @@ -282,7 +351,7 @@ int snd_card_new(struct device *parent, int idx, const char *xid, dev_err(parent, "unable to create card info\n"); goto __error_ctl; } - *card_ret = card; + return 0;
__error_ctl: @@ -291,7 +360,6 @@ int snd_card_new(struct device *parent, int idx, const char *xid, put_device(&card->card_dev); return err; } -EXPORT_SYMBOL(snd_card_new);
/* return non-zero if a card is already locked */ int snd_card_locked(int card) @@ -484,6 +552,7 @@ EXPORT_SYMBOL_GPL(snd_card_disconnect_sync);
static int snd_card_do_free(struct snd_card *card) { + card->releasing = true; #if IS_ENABLED(CONFIG_SND_MIXER_OSS) if (snd_mixer_oss_notify_callback) snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE); @@ -498,7 +567,8 @@ static int snd_card_do_free(struct snd_card *card) } if (card->release_completion) complete(card->release_completion); - kfree(card); + if (!card->managed) + kfree(card); return 0; }
@@ -539,6 +609,9 @@ int snd_card_free(struct snd_card *card) struct completion released; int ret;
+ if (card->releasing) + return 0; + init_completion(&released); card->release_completion = &released; ret = snd_card_free_when_closed(card); @@ -748,6 +821,11 @@ int snd_card_add_dev_attr(struct snd_card *card, } EXPORT_SYMBOL_GPL(snd_card_add_dev_attr);
+static void trigger_card_free(void *data) +{ + snd_card_free(data); +} + /** * snd_card_register - register the soundcard * @card: soundcard structure @@ -771,6 +849,15 @@ int snd_card_register(struct snd_card *card) if (err < 0) return err; card->registered = true; + } else { + if (card->managed) + devm_remove_action(card->dev, trigger_card_free, card); + } + + if (card->managed) { + err = devm_add_action(card->dev, trigger_card_free, card); + if (err < 0) + return err; }
if ((err = snd_device_register_all(card)) < 0)
This patch refactors the intel8x0 and intel8x0m driver codes using devres and gets rid of the driver remove callback.
The conversion is fairly straightforward: each API call is replaced with the device-managed API function, e.g. pci_enable_device() -> pcim_enable_device(), and so on. The buffer descriptor list is allocated with a new API, snd_devm_alloc_pages().
A slight code structure change is that the intel8x0 object is allocated as a card's private_data instead of the own lowlevel snd_device object. This simplifies the resource management. And, the take-down procedure is triggered via card->private_free, and it's registered at the end of the whole initialization, i.e. after the all resources get properly managed.
The only not-devres-managed resource is the irq handler. Since we need to release at suspend and re-acquire at resume (otherwise something weird happens on some machines), this is still managed manually. But the rest are all freed automatically.
The end result is a good amount of code reduction.
Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/pci/intel8x0.c | 143 ++++++++++++++---------------------------- sound/pci/intel8x0m.c | 143 ++++++++++++++---------------------------- 2 files changed, 92 insertions(+), 194 deletions(-)
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 9517f9b8f1d4..662d5c9109f5 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -415,7 +415,7 @@ struct intel8x0 { spinlock_t reg_lock; u32 bdbars_count; - struct snd_dma_buffer bdbars; + struct snd_dma_buffer *bdbars; u32 int_sta_reg; /* interrupt status register */ u32 int_sta_mask; /* interrupt status mask */ }; @@ -2567,8 +2567,9 @@ static int snd_intel8x0_chip_init(struct intel8x0 *chip, int probing) return 0; }
-static int snd_intel8x0_free(struct intel8x0 *chip) +static void snd_intel8x0_free(struct snd_card *card) { + struct intel8x0 *chip = card->private_data; unsigned int i;
if (chip->irq < 0) @@ -2591,16 +2592,6 @@ static int snd_intel8x0_free(struct intel8x0 *chip) __hw_end: if (chip->irq >= 0) free_irq(chip->irq, chip); - if (chip->bdbars.area) - snd_dma_free_pages(&chip->bdbars); - if (chip->addr) - pci_iounmap(chip->pci, chip->addr); - if (chip->bmaddr) - pci_iounmap(chip->pci, chip->bmaddr); - pci_release_regions(chip->pci); - pci_disable_device(chip->pci); - kfree(chip); - return 0; }
#ifdef CONFIG_PM_SLEEP @@ -2871,12 +2862,6 @@ static void snd_intel8x0_proc_init(struct intel8x0 *chip) snd_info_set_text_ops(entry, chip, snd_intel8x0_proc_read); }
-static int snd_intel8x0_dev_free(struct snd_device *device) -{ - struct intel8x0 *chip = device->device_data; - return snd_intel8x0_free(chip); -} - struct ich_reg_info { unsigned int int_sta_mask; unsigned int offset; @@ -2920,19 +2905,15 @@ static int snd_intel8x0_inside_vm(struct pci_dev *pci) return result; }
-static int snd_intel8x0_create(struct snd_card *card, - struct pci_dev *pci, - unsigned long device_type, - struct intel8x0 **r_intel8x0) +static int snd_intel8x0_init(struct snd_card *card, + struct pci_dev *pci, + unsigned long device_type) { - struct intel8x0 *chip; + struct intel8x0 *chip = card->private_data; int err; unsigned int i; unsigned int int_sta_masks; struct ichdev *ichdev; - static struct snd_device_ops ops = { - .dev_free = snd_intel8x0_dev_free, - };
static unsigned int bdbars[] = { 3, /* DEVICE_INTEL */ @@ -2965,16 +2946,10 @@ static int snd_intel8x0_create(struct snd_card *card, }; struct ich_reg_info *tbl;
- *r_intel8x0 = NULL; - - if ((err = pci_enable_device(pci)) < 0) + err = pcim_enable_device(pci); + if (err < 0) return err;
- chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) { - pci_disable_device(pci); - return -ENOMEM; - } spin_lock_init(&chip->reg_lock); chip->device_type = device_type; chip->card = card; @@ -2999,38 +2974,24 @@ static int snd_intel8x0_create(struct snd_card *card, pci->device == PCI_DEVICE_ID_INTEL_440MX) chip->fix_nocache = 1; /* enable workaround */
- if ((err = pci_request_regions(pci, card->shortname)) < 0) { - kfree(chip); - pci_disable_device(pci); + err = pcim_iomap_regions(pci, -1, card->shortname); + if (err < 0) return err; - }
if (device_type == DEVICE_ALI) { /* ALI5455 has no ac97 region */ - chip->bmaddr = pci_iomap(pci, 0, 0); - goto port_inited; - } - - if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) /* ICH4 and Nforce */ - chip->addr = pci_iomap(pci, 2, 0); - else - chip->addr = pci_iomap(pci, 0, 0); - if (!chip->addr) { - dev_err(card->dev, "AC'97 space ioremap problem\n"); - snd_intel8x0_free(chip); - return -EIO; + chip->bmaddr = pcim_iomap_table(pci)[0]; + } else { + if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) /* ICH4 and Nforce */ + chip->addr = pcim_iomap_table(pci)[2]; + else + chip->addr = pcim_iomap_table(pci)[0]; + if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) /* ICH4 */ + chip->bmaddr = pcim_iomap_table(pci)[3]; + else + chip->bmaddr = pcim_iomap_table(pci)[1]; } - if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) /* ICH4 */ - chip->bmaddr = pci_iomap(pci, 3, 0); - else - chip->bmaddr = pci_iomap(pci, 1, 0);
- port_inited: - if (!chip->bmaddr) { - dev_err(card->dev, "Controller space ioremap problem\n"); - snd_intel8x0_free(chip); - return -EIO; - } chip->bdbars_count = bdbars[device_type];
/* initialize offsets */ @@ -3066,10 +3027,10 @@ static int snd_intel8x0_create(struct snd_card *card,
/* allocate buffer descriptor lists */ /* the start of each lists must be aligned to 8 bytes */ - if (snd_dma_alloc_pages(intel8x0_dma_type(chip), snd_dma_pci_data(pci), - chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2, - &chip->bdbars) < 0) { - snd_intel8x0_free(chip); + chip->bdbars = snd_devm_alloc_pages(&pci->dev, intel8x0_dma_type(chip), + chip->bdbars_count * sizeof(u32) * + ICH_MAX_FRAGS * 2); + if (IS_ERR(chip->bdbars)) { dev_err(card->dev, "cannot allocate buffer descriptors\n"); return -ENOMEM; } @@ -3078,9 +3039,9 @@ static int snd_intel8x0_create(struct snd_card *card, int_sta_masks = 0; for (i = 0; i < chip->bdbars_count; i++) { ichdev = &chip->ichd[i]; - ichdev->bdbar = ((__le32 *)chip->bdbars.area) + + ichdev->bdbar = ((__le32 *)chip->bdbars->area) + (i * ICH_MAX_FRAGS * 2); - ichdev->bdbar_addr = chip->bdbars.addr + + ichdev->bdbar_addr = chip->bdbars->addr + (i * sizeof(u32) * ICH_MAX_FRAGS * 2); int_sta_masks |= ichdev->int_sta_mask; } @@ -3113,26 +3074,23 @@ static int snd_intel8x0_create(struct snd_card *card, for (i = 0; i < chip->max_codecs; i++) chip->codec_isr_bits |= chip->codec_bit[i];
- if ((err = snd_intel8x0_chip_init(chip, 1)) < 0) { - snd_intel8x0_free(chip); + err = snd_intel8x0_chip_init(chip, 1); + if (err < 0) return err; - }
/* request irq after initializaing int_sta_mask, etc */ + /* NOTE: we don't use devm version here since it's released / + * re-acquired in PM callbacks. + * It's released explicitly in snd_intel8x0_free(), too. + */ if (request_irq(pci->irq, snd_intel8x0_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); - snd_intel8x0_free(chip); return -EBUSY; } chip->irq = pci->irq; + card->private_free = snd_intel8x0_free;
- if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { - snd_intel8x0_free(chip); - return err; - } - - *r_intel8x0 = chip; return 0; }
@@ -3198,9 +3156,11 @@ static int snd_intel8x0_probe(struct pci_dev *pci, int err; struct shortname_table *name;
- err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card); + err = snd_devm_card_new(&pci->dev, index, id, THIS_MODULE, + sizeof(*chip), &card); if (err < 0) return err; + chip = card->private_data;
if (spdif_aclink < 0) spdif_aclink = check_default_spdif_aclink(pci); @@ -3234,21 +3194,16 @@ static int snd_intel8x0_probe(struct pci_dev *pci, buggy_irq = 0; }
- if ((err = snd_intel8x0_create(card, pci, pci_id->driver_data, - &chip)) < 0) { - snd_card_free(card); + err = snd_intel8x0_init(card, pci, pci_id->driver_data); + if (err < 0) return err; - } - card->private_data = chip;
- if ((err = snd_intel8x0_mixer(chip, ac97_clock, ac97_quirk)) < 0) { - snd_card_free(card); + err = snd_intel8x0_mixer(chip, ac97_clock, ac97_quirk); + if (err < 0) return err; - } - if ((err = snd_intel8x0_pcm(chip)) < 0) { - snd_card_free(card); + err = snd_intel8x0_pcm(chip); + if (err < 0) return err; - } snd_intel8x0_proc_init(chip);
@@ -3265,24 +3220,18 @@ static int snd_intel8x0_probe(struct pci_dev *pci, } }
- if ((err = snd_card_register(card)) < 0) { - snd_card_free(card); + err = snd_card_register(card); + if (err < 0) return err; - } + pci_set_drvdata(pci, card); return 0; }
-static void snd_intel8x0_remove(struct pci_dev *pci) -{ - snd_card_free(pci_get_drvdata(pci)); -} - static struct pci_driver intel8x0_driver = { .name = KBUILD_MODNAME, .id_table = snd_intel8x0_ids, .probe = snd_intel8x0_probe, - .remove = snd_intel8x0_remove, .driver = { .pm = INTEL8X0_PM_OPS, }, diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index c84629190cba..22fc834f48c0 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -212,7 +212,7 @@ struct intel8x0m {
spinlock_t reg_lock; - struct snd_dma_buffer bdbars; + struct snd_dma_buffer *bdbars; u32 bdbars_count; u32 int_sta_reg; /* interrupt status register */ u32 int_sta_mask; /* interrupt status mask */ @@ -990,8 +990,9 @@ static int snd_intel8x0m_chip_init(struct intel8x0m *chip, int probing) return 0; }
-static int snd_intel8x0m_free(struct intel8x0m *chip) +static void snd_intel8x0m_free(struct snd_card *card) { + struct intel8x0m *chip = card->private_data; unsigned int i;
if (chip->irq < 0) @@ -1005,16 +1006,6 @@ static int snd_intel8x0m_free(struct intel8x0m *chip) __hw_end: if (chip->irq >= 0) free_irq(chip->irq, chip); - if (chip->bdbars.area) - snd_dma_free_pages(&chip->bdbars); - if (chip->addr) - pci_iounmap(chip->pci, chip->addr); - if (chip->bmaddr) - pci_iounmap(chip->pci, chip->bmaddr); - pci_release_regions(chip->pci); - pci_disable_device(chip->pci); - kfree(chip); - return 0; }
#ifdef CONFIG_PM_SLEEP @@ -1093,84 +1084,54 @@ static void snd_intel8x0m_proc_init(struct intel8x0m *chip) snd_info_set_text_ops(entry, chip, snd_intel8x0m_proc_read); }
-static int snd_intel8x0m_dev_free(struct snd_device *device) -{ - struct intel8x0m *chip = device->device_data; - return snd_intel8x0m_free(chip); -} - struct ich_reg_info { unsigned int int_sta_mask; unsigned int offset; };
-static int snd_intel8x0m_create(struct snd_card *card, - struct pci_dev *pci, - unsigned long device_type, - struct intel8x0m **r_intel8x0m) +static int snd_intel8x0m_init(struct snd_card *card, + struct pci_dev *pci, + unsigned long device_type) { - struct intel8x0m *chip; + struct intel8x0m *chip = card->private_data; int err; unsigned int i; unsigned int int_sta_masks; struct ichdev *ichdev; - static struct snd_device_ops ops = { - .dev_free = snd_intel8x0m_dev_free, - }; static struct ich_reg_info intel_regs[2] = { { ICH_MIINT, 0 }, { ICH_MOINT, 0x10 }, }; struct ich_reg_info *tbl;
- *r_intel8x0m = NULL; - - if ((err = pci_enable_device(pci)) < 0) + err = pcim_enable_device(pci); + if (err < 0) return err;
- chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) { - pci_disable_device(pci); - return -ENOMEM; - } spin_lock_init(&chip->reg_lock); chip->device_type = device_type; chip->card = card; chip->pci = pci; chip->irq = -1;
- if ((err = pci_request_regions(pci, card->shortname)) < 0) { - kfree(chip); - pci_disable_device(pci); + err = pcim_iomap_regions(pci, -1, card->shortname); + if (err < 0) return err; - }
if (device_type == DEVICE_ALI) { /* ALI5455 has no ac97 region */ - chip->bmaddr = pci_iomap(pci, 0, 0); - goto port_inited; - } - - if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) /* ICH4 and Nforce */ - chip->addr = pci_iomap(pci, 2, 0); - else - chip->addr = pci_iomap(pci, 0, 0); - if (!chip->addr) { - dev_err(card->dev, "AC'97 space ioremap problem\n"); - snd_intel8x0m_free(chip); - return -EIO; - } - if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) /* ICH4 */ - chip->bmaddr = pci_iomap(pci, 3, 0); - else - chip->bmaddr = pci_iomap(pci, 1, 0); - if (!chip->bmaddr) { - dev_err(card->dev, "Controller space ioremap problem\n"); - snd_intel8x0m_free(chip); - return -EIO; + chip->bmaddr = pcim_iomap_table(pci)[0]; + } else { + if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) /* ICH4 and Nforce */ + chip->addr = pcim_iomap_table(pci)[2]; + else + chip->addr = pcim_iomap_table(pci)[0]; + if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) /* ICH4 */ + chip->bmaddr = pcim_iomap_table(pci)[3]; + else + chip->bmaddr = pcim_iomap_table(pci)[1]; }
- port_inited: /* initialize offsets */ chip->bdbars_count = 2; tbl = intel_regs; @@ -1196,19 +1157,19 @@ static int snd_intel8x0m_create(struct snd_card *card,
/* allocate buffer descriptor lists */ /* the start of each lists must be aligned to 8 bytes */ - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), - chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2, - &chip->bdbars) < 0) { - snd_intel8x0m_free(chip); + chip->bdbars = snd_devm_alloc_pages(&pci->dev, SNDRV_DMA_TYPE_DEV, + chip->bdbars_count * sizeof(u32) * + ICH_MAX_FRAGS * 2); + if (IS_ERR(chip->bdbars)) return -ENOMEM; - } + /* tables must be aligned to 8 bytes here, but the kernel pages are much bigger, so we don't care (on i386) */ int_sta_masks = 0; for (i = 0; i < chip->bdbars_count; i++) { ichdev = &chip->ichd[i]; - ichdev->bdbar = ((__le32 *)chip->bdbars.area) + (i * ICH_MAX_FRAGS * 2); - ichdev->bdbar_addr = chip->bdbars.addr + (i * sizeof(u32) * ICH_MAX_FRAGS * 2); + ichdev->bdbar = ((__le32 *)chip->bdbars->area) + (i * ICH_MAX_FRAGS * 2); + ichdev->bdbar_addr = chip->bdbars->addr + (i * sizeof(u32) * ICH_MAX_FRAGS * 2); int_sta_masks |= ichdev->int_sta_mask; } chip->int_sta_reg = ICH_REG_GLOB_STA; @@ -1216,25 +1177,22 @@ static int snd_intel8x0m_create(struct snd_card *card,
pci_set_master(pci);
- if ((err = snd_intel8x0m_chip_init(chip, 1)) < 0) { - snd_intel8x0m_free(chip); + err = snd_intel8x0m_chip_init(chip, 1); + if (err < 0) return err; - }
+ /* NOTE: we don't use devm version here since it's released / + * re-acquired in PM callbacks. + * It's released explicitly in snd_intel8x0m_free(), too. + */ if (request_irq(pci->irq, snd_intel8x0m_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); - snd_intel8x0m_free(chip); return -EBUSY; } chip->irq = pci->irq; + card->private_free = snd_intel8x0m_free;
- if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { - snd_intel8x0m_free(chip); - return err; - } - - *r_intel8x0m = chip; return 0; }
@@ -1272,9 +1230,11 @@ static int snd_intel8x0m_probe(struct pci_dev *pci, int err; struct shortname_table *name;
- err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card); + err = snd_devm_card_new(&pci->dev, index, id, THIS_MODULE, + sizeof(*chip), &card); if (err < 0) return err; + chip = card->private_data;
strcpy(card->driver, "ICH-MODEM"); strcpy(card->shortname, "Intel ICH"); @@ -1286,44 +1246,33 @@ static int snd_intel8x0m_probe(struct pci_dev *pci, } strcat(card->shortname," Modem");
- if ((err = snd_intel8x0m_create(card, pci, pci_id->driver_data, &chip)) < 0) { - snd_card_free(card); + err = snd_intel8x0m_init(card, pci, pci_id->driver_data); + if (err < 0) return err; - } - card->private_data = chip;
- if ((err = snd_intel8x0m_mixer(chip, ac97_clock)) < 0) { - snd_card_free(card); + err = snd_intel8x0m_mixer(chip, ac97_clock); + if (err < 0) return err; - } - if ((err = snd_intel8x0m_pcm(chip)) < 0) { - snd_card_free(card); + err = snd_intel8x0m_pcm(chip); + if (err < 0) return err; - } snd_intel8x0m_proc_init(chip);
sprintf(card->longname, "%s at irq %i", card->shortname, chip->irq);
- if ((err = snd_card_register(card)) < 0) { - snd_card_free(card); + err = snd_card_register(card); + if (err < 0) return err; - } pci_set_drvdata(pci, card); return 0; }
-static void snd_intel8x0m_remove(struct pci_dev *pci) -{ - snd_card_free(pci_get_drvdata(pci)); -} - static struct pci_driver intel8x0m_driver = { .name = KBUILD_MODNAME, .id_table = snd_intel8x0m_ids, .probe = snd_intel8x0m_probe, - .remove = snd_intel8x0m_remove, .driver = { .pm = INTEL8X0M_PM_OPS, },
Like the previous patch, this patch converts the resource allocations with device-managed API calls, so that we can reduce resource-free calls.
The atiixp drivers are simpler than intel8x0, and even the irq can be allocated with devres.
The end result is a good amount of code reduction.
Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/pci/atiixp.c | 104 +++++++++++---------------------------- sound/pci/atiixp_modem.c | 104 +++++++++++---------------------------- 2 files changed, 60 insertions(+), 148 deletions(-)
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index a1e4944dcfe8..3764f14d1bec 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -1557,84 +1557,44 @@ static void snd_atiixp_proc_init(struct atiixp *chip) * destructor */
-static int snd_atiixp_free(struct atiixp *chip) +static void snd_atiixp_free(struct snd_card *card) { - if (chip->irq < 0) - goto __hw_end; - snd_atiixp_chip_stop(chip); - - __hw_end: - if (chip->irq >= 0) - free_irq(chip->irq, chip); - iounmap(chip->remap_addr); - pci_release_regions(chip->pci); - pci_disable_device(chip->pci); - kfree(chip); - return 0; -} - -static int snd_atiixp_dev_free(struct snd_device *device) -{ - struct atiixp *chip = device->device_data; - return snd_atiixp_free(chip); + snd_atiixp_chip_stop(card->private_data); }
/* * constructor for chip instance */ -static int snd_atiixp_create(struct snd_card *card, - struct pci_dev *pci, - struct atiixp **r_chip) +static int snd_atiixp_init(struct snd_card *card, struct pci_dev *pci) { - static struct snd_device_ops ops = { - .dev_free = snd_atiixp_dev_free, - }; - struct atiixp *chip; + struct atiixp *chip = card->private_data; int err;
- if ((err = pci_enable_device(pci)) < 0) + err = pcim_enable_device(pci); + if (err < 0) return err;
- chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) { - pci_disable_device(pci); - return -ENOMEM; - } - spin_lock_init(&chip->reg_lock); mutex_init(&chip->open_mutex); chip->card = card; chip->pci = pci; chip->irq = -1; - if ((err = pci_request_regions(pci, "ATI IXP AC97")) < 0) { - pci_disable_device(pci); - kfree(chip); + err = pcim_iomap_regions(pci, 1 << 0, "ATI IXP AC97"); + if (err < 0) return err; - } chip->addr = pci_resource_start(pci, 0); - chip->remap_addr = pci_ioremap_bar(pci, 0); - if (chip->remap_addr == NULL) { - dev_err(card->dev, "AC'97 space ioremap problem\n"); - snd_atiixp_free(chip); - return -EIO; - } + chip->remap_addr = pcim_iomap_table(pci)[0];
- if (request_irq(pci->irq, snd_atiixp_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + if (devm_request_irq(&pci->dev, pci->irq, snd_atiixp_interrupt, + IRQF_SHARED, KBUILD_MODNAME, chip)) { dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); - snd_atiixp_free(chip); return -EBUSY; } chip->irq = pci->irq; + card->private_free = snd_atiixp_free; pci_set_master(pci); synchronize_irq(chip->irq);
- if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { - snd_atiixp_free(chip); - return err; - } - - *r_chip = chip; return 0; }
@@ -1646,26 +1606,31 @@ static int snd_atiixp_probe(struct pci_dev *pci, struct atiixp *chip; int err;
- err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card); + err = snd_devm_card_new(&pci->dev, index, id, THIS_MODULE, + sizeof(*chip), &card); if (err < 0) return err; + chip = card->private_data;
strcpy(card->driver, spdif_aclink ? "ATIIXP" : "ATIIXP-SPDMA"); strcpy(card->shortname, "ATI IXP"); - if ((err = snd_atiixp_create(card, pci, &chip)) < 0) - goto __error; - card->private_data = chip; + err = snd_atiixp_init(card, pci); + if (err < 0) + return err;
- if ((err = snd_atiixp_aclink_reset(chip)) < 0) - goto __error; + err = snd_atiixp_aclink_reset(chip); + if (err < 0) + return err;
chip->spdif_over_aclink = spdif_aclink;
- if ((err = snd_atiixp_mixer_new(chip, ac97_clock, ac97_quirk)) < 0) - goto __error; + err = snd_atiixp_mixer_new(chip, ac97_clock, ac97_quirk); + if (err < 0) + return err;
- if ((err = snd_atiixp_pcm_new(chip)) < 0) - goto __error; + err = snd_atiixp_pcm_new(chip); + if (err < 0) + return err; snd_atiixp_proc_init(chip);
@@ -1677,27 +1642,18 @@ static int snd_atiixp_probe(struct pci_dev *pci, chip->ac97[0] ? snd_ac97_get_short_name(chip->ac97[0]) : "?", chip->addr, chip->irq);
- if ((err = snd_card_register(card)) < 0) - goto __error; + err = snd_card_register(card); + if (err < 0) + return err;
pci_set_drvdata(pci, card); return 0; - - __error: - snd_card_free(card); - return err; -} - -static void snd_atiixp_remove(struct pci_dev *pci) -{ - snd_card_free(pci_get_drvdata(pci)); }
static struct pci_driver atiixp_driver = { .name = KBUILD_MODNAME, .id_table = snd_atiixp_ids, .probe = snd_atiixp_probe, - .remove = snd_atiixp_remove, .driver = { .pm = SND_ATIIXP_PM_OPS, }, diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index dc1de860cedf..207f2be1d73e 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -1183,84 +1183,44 @@ static void snd_atiixp_proc_init(struct atiixp_modem *chip) * destructor */
-static int snd_atiixp_free(struct atiixp_modem *chip) +static void snd_atiixp_free(struct snd_card *card) { - if (chip->irq < 0) - goto __hw_end; - snd_atiixp_chip_stop(chip); - - __hw_end: - if (chip->irq >= 0) - free_irq(chip->irq, chip); - iounmap(chip->remap_addr); - pci_release_regions(chip->pci); - pci_disable_device(chip->pci); - kfree(chip); - return 0; -} - -static int snd_atiixp_dev_free(struct snd_device *device) -{ - struct atiixp_modem *chip = device->device_data; - return snd_atiixp_free(chip); + snd_atiixp_chip_stop(card->private_data); }
/* * constructor for chip instance */ -static int snd_atiixp_create(struct snd_card *card, - struct pci_dev *pci, - struct atiixp_modem **r_chip) +static int snd_atiixp_init(struct snd_card *card, struct pci_dev *pci) { - static struct snd_device_ops ops = { - .dev_free = snd_atiixp_dev_free, - }; - struct atiixp_modem *chip; + struct atiixp_modem *chip = card->private_data; int err;
- if ((err = pci_enable_device(pci)) < 0) + err = pcim_enable_device(pci); + if (err < 0) return err;
- chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) { - pci_disable_device(pci); - return -ENOMEM; - } - spin_lock_init(&chip->reg_lock); mutex_init(&chip->open_mutex); chip->card = card; chip->pci = pci; chip->irq = -1; - if ((err = pci_request_regions(pci, "ATI IXP MC97")) < 0) { - kfree(chip); - pci_disable_device(pci); + err = pcim_iomap_regions(pci, 1 << 0, "ATI IXP MC97"); + if (err < 0) return err; - } chip->addr = pci_resource_start(pci, 0); - chip->remap_addr = pci_ioremap_bar(pci, 0); - if (chip->remap_addr == NULL) { - dev_err(card->dev, "AC'97 space ioremap problem\n"); - snd_atiixp_free(chip); - return -EIO; - } + chip->remap_addr = pcim_iomap_table(pci)[0];
- if (request_irq(pci->irq, snd_atiixp_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + if (devm_request_irq(&pci->dev, pci->irq, snd_atiixp_interrupt, + IRQF_SHARED, KBUILD_MODNAME, chip)) { dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); - snd_atiixp_free(chip); return -EBUSY; } chip->irq = pci->irq; + card->private_free = snd_atiixp_free; pci_set_master(pci); synchronize_irq(chip->irq);
- if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { - snd_atiixp_free(chip); - return err; - } - - *r_chip = chip; return 0; }
@@ -1272,24 +1232,29 @@ static int snd_atiixp_probe(struct pci_dev *pci, struct atiixp_modem *chip; int err;
- err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card); + err = snd_devm_card_new(&pci->dev, index, id, THIS_MODULE, + sizeof(*chip), &card); if (err < 0) return err; + chip = card->private_data;
strcpy(card->driver, "ATIIXP-MODEM"); strcpy(card->shortname, "ATI IXP Modem"); - if ((err = snd_atiixp_create(card, pci, &chip)) < 0) - goto __error; - card->private_data = chip; + err = snd_atiixp_init(card, pci); + if (err < 0) + return err;
- if ((err = snd_atiixp_aclink_reset(chip)) < 0) - goto __error; + err = snd_atiixp_aclink_reset(chip); + if (err < 0) + return err;
- if ((err = snd_atiixp_mixer_new(chip, ac97_clock)) < 0) - goto __error; + err = snd_atiixp_mixer_new(chip, ac97_clock); + if (err < 0) + return err;
- if ((err = snd_atiixp_pcm_new(chip)) < 0) - goto __error; + err = snd_atiixp_pcm_new(chip); + if (err < 0) + return err; snd_atiixp_proc_init(chip);
@@ -1298,27 +1263,18 @@ static int snd_atiixp_probe(struct pci_dev *pci, sprintf(card->longname, "%s rev %x at 0x%lx, irq %i", card->shortname, pci->revision, chip->addr, chip->irq);
- if ((err = snd_card_register(card)) < 0) - goto __error; + err = snd_card_register(card); + if (err < 0) + return err;
pci_set_drvdata(pci, card); return 0; - - __error: - snd_card_free(card); - return err; -} - -static void snd_atiixp_remove(struct pci_dev *pci) -{ - snd_card_free(pci_get_drvdata(pci)); }
static struct pci_driver atiixp_modem_driver = { .name = KBUILD_MODNAME, .id_table = snd_atiixp_ids, .probe = snd_atiixp_probe, - .remove = snd_atiixp_remove, .driver = { .pm = SND_ATIIXP_PM_OPS, },
This patch is an attempt to slightly simplify the resource management in HD-audio code, by using some device-managed APIs. A few resources like PCI enablement, PCI resources and the card object are managed via devres now. But most of codes dealing with HD-audio core stuff couldn't be changed so much, hence the changes in this patch are pretty small in the end.
Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/pci/hda/hda_controller.h | 1 - sound/pci/hda/hda_intel.c | 43 ++++++++-------------------------- 2 files changed, 10 insertions(+), 34 deletions(-)
diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index c95097bb5a0c..16f2285847b3 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -156,7 +156,6 @@ struct azx { unsigned int snoop:1; unsigned int uc_buffer:1; /* non-cached pages for stream buffers */ unsigned int align_buffer_size:1; - unsigned int region_requested:1; unsigned int disabled:1; /* disabled by vga_switcheroo */
/* GTS present */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 4e64595b381b..7a697db7a6a0 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1318,18 +1318,11 @@ static int azx_free(struct azx *chip)
if (bus->irq >= 0) free_irq(bus->irq, (void*)chip); - if (chip->msi) - pci_disable_msi(chip->pci); - iounmap(bus->remap_addr);
azx_free_stream_pages(chip); azx_free_streams(chip); snd_hdac_bus_exit(bus);
- if (chip->region_requested) - pci_release_regions(chip->pci); - - pci_disable_device(chip->pci); #ifdef CONFIG_SND_HDA_PATCH_LOADER release_firmware(chip->fw); #endif @@ -1657,15 +1650,13 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
*rchip = NULL;
- err = pci_enable_device(pci); + err = pcim_enable_device(pci); if (err < 0) return err;
hda = kzalloc(sizeof(*hda), GFP_KERNEL); - if (!hda) { - pci_disable_device(pci); + if (!hda) return -ENOMEM; - }
chip = &hda->chip; mutex_init(&chip->open_mutex); @@ -1707,7 +1698,6 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, err = azx_bus_init(chip, model[dev], &pci_hda_io_ops); if (err < 0) { kfree(hda); - pci_disable_device(pci); return err; }
@@ -1751,17 +1741,12 @@ static int azx_first_init(struct azx *chip) } #endif
- err = pci_request_regions(pci, "ICH HD audio"); + err = pcim_iomap_regions(pci, 1 << 0, "ICH HD audio"); if (err < 0) return err; - chip->region_requested = 1;
bus->addr = pci_resource_start(pci, 0); - bus->remap_addr = pci_ioremap_bar(pci, 0); - if (bus->remap_addr == NULL) { - dev_err(card->dev, "ioremap error\n"); - return -ENXIO; - } + bus->remap_addr = pcim_iomap_table(pci)[0];
if (chip->driver_type == AZX_DRIVER_SKL) snd_hdac_bus_parse_capabilities(bus); @@ -2057,16 +2042,14 @@ static int azx_probe(struct pci_dev *pci, return -ENOENT; }
- err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, - 0, &card); - if (err < 0) { - dev_err(&pci->dev, "Error creating card!\n"); + err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, 0, + &card); + if (err < 0) return err; - }
err = azx_create(card, pci, dev, pci_id->driver_data, &chip); if (err < 0) - goto out_free; + return err; card->private_data = chip; hda = container_of(chip, struct hda_intel, chip);
@@ -2075,7 +2058,7 @@ static int azx_probe(struct pci_dev *pci, err = register_vga_switcheroo(chip); if (err < 0) { dev_err(card->dev, "Error registering vga_switcheroo client\n"); - goto out_free; + return err; }
if (check_hdmi_disabled(pci)) { @@ -2094,7 +2077,7 @@ static int azx_probe(struct pci_dev *pci, &pci->dev, GFP_KERNEL, card, azx_firmware_cb); if (err < 0) - goto out_free; + return err; schedule_probe = false; /* continued in azx_firmware_cb() */ } #endif /* CONFIG_SND_HDA_PATCH_LOADER */ @@ -2111,10 +2094,6 @@ static int azx_probe(struct pci_dev *pci, if (chip->disabled) complete_all(&hda->probe_wait); return 0; - -out_free: - snd_card_free(card); - return err; }
#ifdef CONFIG_PM @@ -2304,8 +2283,6 @@ static void azx_remove(struct pci_dev *pci) device_unlock(&pci->dev); cancel_work_sync(&hda->probe_work); device_lock(&pci->dev); - - snd_card_free(card); } }
participants (1)
-
Takashi Iwai