diff mbox

fm801: move to pcim_* and devm_* functions

Message ID 1420587617-28521-1-git-send-email-andy.shevchenko@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Andy Shevchenko Jan. 6, 2015, 11:40 p.m. UTC
The managed functions allow to get ->probe() and ->remove() simplier.
This patch converts code to use managed functions.

While here remove the dead code and fix the value printed in error
message.

Signed-off-by: Andy Shevchenko <andy.shevchenko@gmail.com>
---
 sound/pci/fm801.c | 29 +++++++----------------------
 1 file changed, 7 insertions(+), 22 deletions(-)

Comments

Takashi Iwai Jan. 7, 2015, 7:11 a.m. UTC | #1
At Wed,  7 Jan 2015 01:40:17 +0200,
Andy Shevchenko wrote:
> 
> The managed functions allow to get ->probe() and ->remove() simplier.
> This patch converts code to use managed functions.

This doesn't work well because of the order of release calls in
device_release().  devres_release_all() is called at first before
anything else.  Thus the card's free callback would be called after
it, and snd_fm801_free() touches the hardware before disabling.


Takashi

> While here remove the dead code and fix the value printed in error
> message.
> 
> Signed-off-by: Andy Shevchenko <andy.shevchenko@gmail.com>
> ---
>  sound/pci/fm801.c | 29 +++++++----------------------
>  1 file changed, 7 insertions(+), 22 deletions(-)
> 
> diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
> index dcda3c1..2708500 100644
> --- a/sound/pci/fm801.c
> +++ b/sound/pci/fm801.c
> @@ -1178,12 +1178,8 @@ static int snd_fm801_free(struct fm801 *chip)
>  		v4l2_device_unregister(&chip->v4l2_dev);
>  	}
>  #endif
> -	if (chip->irq >= 0)
> -		free_irq(chip->irq, chip);
>  	pci_release_regions(chip->pci);
> -	pci_disable_device(chip->pci);
>  
> -	kfree(chip);
>  	return 0;
>  }
>  
> @@ -1206,28 +1202,23 @@ static int snd_fm801_create(struct snd_card *card,
>  	};
>  
>  	*rchip = NULL;
> -	if ((err = pci_enable_device(pci)) < 0)
> +	if ((err = pcim_enable_device(pci)) < 0)
>  		return err;
> -	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
> -	if (chip == NULL) {
> -		pci_disable_device(pci);
> +	chip = devm_kzalloc(&pci->dev, sizeof(*chip), GFP_KERNEL);
> +	if (chip == NULL)
>  		return -ENOMEM;
> -	}
>  	spin_lock_init(&chip->reg_lock);
>  	chip->card = card;
>  	chip->pci = pci;
>  	chip->irq = -1;
>  	chip->tea575x_tuner = tea575x_tuner;
> -	if ((err = pci_request_regions(pci, "FM801")) < 0) {
> -		kfree(chip);
> -		pci_disable_device(pci);
> +	if ((err = pci_request_regions(pci, "FM801")) < 0)
>  		return err;
> -	}
>  	chip->port = pci_resource_start(pci, 0);
>  	if ((tea575x_tuner & TUNER_ONLY) == 0) {
> -		if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED,
> -				KBUILD_MODNAME, chip)) {
> -			dev_err(card->dev, "unable to grab IRQ %d\n", chip->irq);
> +		if (devm_request_irq(&pci->dev, pci->irq, snd_fm801_interrupt,
> +				IRQF_SHARED, KBUILD_MODNAME, chip)) {
> +			dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
>  			snd_fm801_free(chip);
>  			return -EBUSY;
>  		}
> @@ -1242,12 +1233,6 @@ static int snd_fm801_create(struct snd_card *card,
>  	/* init might set tuner access method */
>  	tea575x_tuner = chip->tea575x_tuner;
>  
> -	if (chip->irq >= 0 && (tea575x_tuner & TUNER_ONLY)) {
> -		pci_clear_master(pci);
> -		free_irq(chip->irq, chip);
> -		chip->irq = -1;
> -	}
> -
>  	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
>  		snd_fm801_free(chip);
>  		return err;
> -- 
> 1.8.3.101.g727a46b
>
Andy Shevchenko Jan. 7, 2015, 10:54 a.m. UTC | #2
On Wed, Jan 7, 2015 at 9:11 AM, Takashi Iwai <tiwai@suse.de> wrote:
> At Wed,  7 Jan 2015 01:40:17 +0200,
> Andy Shevchenko wrote:
>>
>> The managed functions allow to get ->probe() and ->remove() simplier.
>> This patch converts code to use managed functions.
>
> This doesn't work well because of the order of release calls in
> device_release().  devres_release_all() is called at first before
> anything else.  Thus the card's free callback would be called after
> it, and snd_fm801_free() touches the hardware before disabling.
>

Hmm… I didn't get what make those calls. Sound core? The driver is a
normal PCI driver, so resources will be freed *after* ->remove() of
driver was called.
Please, elaborate.

>
> Takashi
>
>> While here remove the dead code and fix the value printed in error
>> message.
>>
>> Signed-off-by: Andy Shevchenko <andy.shevchenko@gmail.com>
>> ---
>>  sound/pci/fm801.c | 29 +++++++----------------------
>>  1 file changed, 7 insertions(+), 22 deletions(-)
>>
>> diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
>> index dcda3c1..2708500 100644
>> --- a/sound/pci/fm801.c
>> +++ b/sound/pci/fm801.c
>> @@ -1178,12 +1178,8 @@ static int snd_fm801_free(struct fm801 *chip)
>>               v4l2_device_unregister(&chip->v4l2_dev);
>>       }
>>  #endif
>> -     if (chip->irq >= 0)
>> -             free_irq(chip->irq, chip);
>>       pci_release_regions(chip->pci);
>> -     pci_disable_device(chip->pci);
>>
>> -     kfree(chip);
>>       return 0;
>>  }
>>
>> @@ -1206,28 +1202,23 @@ static int snd_fm801_create(struct snd_card *card,
>>       };
>>
>>       *rchip = NULL;
>> -     if ((err = pci_enable_device(pci)) < 0)
>> +     if ((err = pcim_enable_device(pci)) < 0)
>>               return err;
>> -     chip = kzalloc(sizeof(*chip), GFP_KERNEL);
>> -     if (chip == NULL) {
>> -             pci_disable_device(pci);
>> +     chip = devm_kzalloc(&pci->dev, sizeof(*chip), GFP_KERNEL);
>> +     if (chip == NULL)
>>               return -ENOMEM;
>> -     }
>>       spin_lock_init(&chip->reg_lock);
>>       chip->card = card;
>>       chip->pci = pci;
>>       chip->irq = -1;
>>       chip->tea575x_tuner = tea575x_tuner;
>> -     if ((err = pci_request_regions(pci, "FM801")) < 0) {
>> -             kfree(chip);
>> -             pci_disable_device(pci);
>> +     if ((err = pci_request_regions(pci, "FM801")) < 0)
>>               return err;
>> -     }
>>       chip->port = pci_resource_start(pci, 0);
>>       if ((tea575x_tuner & TUNER_ONLY) == 0) {
>> -             if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED,
>> -                             KBUILD_MODNAME, chip)) {
>> -                     dev_err(card->dev, "unable to grab IRQ %d\n", chip->irq);
>> +             if (devm_request_irq(&pci->dev, pci->irq, snd_fm801_interrupt,
>> +                             IRQF_SHARED, KBUILD_MODNAME, chip)) {
>> +                     dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
>>                       snd_fm801_free(chip);
>>                       return -EBUSY;
>>               }
>> @@ -1242,12 +1233,6 @@ static int snd_fm801_create(struct snd_card *card,
>>       /* init might set tuner access method */
>>       tea575x_tuner = chip->tea575x_tuner;
>>
>> -     if (chip->irq >= 0 && (tea575x_tuner & TUNER_ONLY)) {
>> -             pci_clear_master(pci);
>> -             free_irq(chip->irq, chip);
>> -             chip->irq = -1;
>> -     }
>> -
>>       if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
>>               snd_fm801_free(chip);
>>               return err;
>> --
>> 1.8.3.101.g727a46b
>>
Takashi Iwai Jan. 7, 2015, 11:27 a.m. UTC | #3
At Wed, 7 Jan 2015 12:54:40 +0200,
Andy Shevchenko wrote:
> 
> On Wed, Jan 7, 2015 at 9:11 AM, Takashi Iwai <tiwai@suse.de> wrote:
> > At Wed,  7 Jan 2015 01:40:17 +0200,
> > Andy Shevchenko wrote:
> >>
> >> The managed functions allow to get ->probe() and ->remove() simplier.
> >> This patch converts code to use managed functions.
> >
> > This doesn't work well because of the order of release calls in
> > device_release().  devres_release_all() is called at first before
> > anything else.  Thus the card's free callback would be called after
> > it, and snd_fm801_free() touches the hardware before disabling.
> >
> 
> Hmm… I didn't get what make those calls. Sound core? The driver is a
> normal PCI driver, so resources will be freed *after* ->remove() of
> driver was called.
> Please, elaborate.

Ah, OK, this seems working, as this is the managed *pci* device that
is a parent of the card device, thus it shall be released after the
children.

But any reason not to use pcim_iomap_regions_request_all()?


thanks,

Takashi

> 
> >
> > Takashi
> >
> >> While here remove the dead code and fix the value printed in error
> >> message.
> >>
> >> Signed-off-by: Andy Shevchenko <andy.shevchenko@gmail.com>
> >> ---
> >>  sound/pci/fm801.c | 29 +++++++----------------------
> >>  1 file changed, 7 insertions(+), 22 deletions(-)
> >>
> >> diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
> >> index dcda3c1..2708500 100644
> >> --- a/sound/pci/fm801.c
> >> +++ b/sound/pci/fm801.c
> >> @@ -1178,12 +1178,8 @@ static int snd_fm801_free(struct fm801 *chip)
> >>               v4l2_device_unregister(&chip->v4l2_dev);
> >>       }
> >>  #endif
> >> -     if (chip->irq >= 0)
> >> -             free_irq(chip->irq, chip);
> >>       pci_release_regions(chip->pci);
> >> -     pci_disable_device(chip->pci);
> >>
> >> -     kfree(chip);
> >>       return 0;
> >>  }
> >>
> >> @@ -1206,28 +1202,23 @@ static int snd_fm801_create(struct snd_card *card,
> >>       };
> >>
> >>       *rchip = NULL;
> >> -     if ((err = pci_enable_device(pci)) < 0)
> >> +     if ((err = pcim_enable_device(pci)) < 0)
> >>               return err;
> >> -     chip = kzalloc(sizeof(*chip), GFP_KERNEL);
> >> -     if (chip == NULL) {
> >> -             pci_disable_device(pci);
> >> +     chip = devm_kzalloc(&pci->dev, sizeof(*chip), GFP_KERNEL);
> >> +     if (chip == NULL)
> >>               return -ENOMEM;
> >> -     }
> >>       spin_lock_init(&chip->reg_lock);
> >>       chip->card = card;
> >>       chip->pci = pci;
> >>       chip->irq = -1;
> >>       chip->tea575x_tuner = tea575x_tuner;
> >> -     if ((err = pci_request_regions(pci, "FM801")) < 0) {
> >> -             kfree(chip);
> >> -             pci_disable_device(pci);
> >> +     if ((err = pci_request_regions(pci, "FM801")) < 0)
> >>               return err;
> >> -     }
> >>       chip->port = pci_resource_start(pci, 0);
> >>       if ((tea575x_tuner & TUNER_ONLY) == 0) {
> >> -             if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED,
> >> -                             KBUILD_MODNAME, chip)) {
> >> -                     dev_err(card->dev, "unable to grab IRQ %d\n", chip->irq);
> >> +             if (devm_request_irq(&pci->dev, pci->irq, snd_fm801_interrupt,
> >> +                             IRQF_SHARED, KBUILD_MODNAME, chip)) {
> >> +                     dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
> >>                       snd_fm801_free(chip);
> >>                       return -EBUSY;
> >>               }
> >> @@ -1242,12 +1233,6 @@ static int snd_fm801_create(struct snd_card *card,
> >>       /* init might set tuner access method */
> >>       tea575x_tuner = chip->tea575x_tuner;
> >>
> >> -     if (chip->irq >= 0 && (tea575x_tuner & TUNER_ONLY)) {
> >> -             pci_clear_master(pci);
> >> -             free_irq(chip->irq, chip);
> >> -             chip->irq = -1;
> >> -     }
> >> -
> >>       if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
> >>               snd_fm801_free(chip);
> >>               return err;
> >> --
> >> 1.8.3.101.g727a46b
> >>
> 
> 
> 
> -- 
> With Best Regards,
> Andy Shevchenko
>
Andy Shevchenko Jan. 7, 2015, 12:20 p.m. UTC | #4
On Wed, Jan 7, 2015 at 1:27 PM, Takashi Iwai <tiwai@suse.de> wrote:
> At Wed, 7 Jan 2015 12:54:40 +0200,
> Andy Shevchenko wrote:
>>
>> On Wed, Jan 7, 2015 at 9:11 AM, Takashi Iwai <tiwai@suse.de> wrote:
>> > At Wed,  7 Jan 2015 01:40:17 +0200,
>> > Andy Shevchenko wrote:
>> >>
>> >> The managed functions allow to get ->probe() and ->remove() simplier.
>> >> This patch converts code to use managed functions.
>> >
>> > This doesn't work well because of the order of release calls in
>> > device_release().  devres_release_all() is called at first before
>> > anything else.  Thus the card's free callback would be called after
>> > it, and snd_fm801_free() touches the hardware before disabling.
>> >
>>
>> Hmm… I didn't get what make those calls. Sound core? The driver is a
>> normal PCI driver, so resources will be freed *after* ->remove() of
>> driver was called.
>> Please, elaborate.
>
> Ah, OK, this seems working, as this is the managed *pci* device that
> is a parent of the card device, thus it shall be released after the
> children.
>
> But any reason not to use pcim_iomap_regions_request_all()?

Yes. I was doubt to put a comment about this. So, the initial idea is
to move to MMIO instead of IO access. That's why you may see previous
patch about fm801_{read,write}w() macros.
I would like to do that later.

>
>
> thanks,
>
> Takashi
>
>>
>> >
>> > Takashi
>> >
>> >> While here remove the dead code and fix the value printed in error
>> >> message.
>> >>
>> >> Signed-off-by: Andy Shevchenko <andy.shevchenko@gmail.com>
>> >> ---
>> >>  sound/pci/fm801.c | 29 +++++++----------------------
>> >>  1 file changed, 7 insertions(+), 22 deletions(-)
>> >>
>> >> diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
>> >> index dcda3c1..2708500 100644
>> >> --- a/sound/pci/fm801.c
>> >> +++ b/sound/pci/fm801.c
>> >> @@ -1178,12 +1178,8 @@ static int snd_fm801_free(struct fm801 *chip)
>> >>               v4l2_device_unregister(&chip->v4l2_dev);
>> >>       }
>> >>  #endif
>> >> -     if (chip->irq >= 0)
>> >> -             free_irq(chip->irq, chip);
>> >>       pci_release_regions(chip->pci);
>> >> -     pci_disable_device(chip->pci);
>> >>
>> >> -     kfree(chip);
>> >>       return 0;
>> >>  }
>> >>
>> >> @@ -1206,28 +1202,23 @@ static int snd_fm801_create(struct snd_card *card,
>> >>       };
>> >>
>> >>       *rchip = NULL;
>> >> -     if ((err = pci_enable_device(pci)) < 0)
>> >> +     if ((err = pcim_enable_device(pci)) < 0)
>> >>               return err;
>> >> -     chip = kzalloc(sizeof(*chip), GFP_KERNEL);
>> >> -     if (chip == NULL) {
>> >> -             pci_disable_device(pci);
>> >> +     chip = devm_kzalloc(&pci->dev, sizeof(*chip), GFP_KERNEL);
>> >> +     if (chip == NULL)
>> >>               return -ENOMEM;
>> >> -     }
>> >>       spin_lock_init(&chip->reg_lock);
>> >>       chip->card = card;
>> >>       chip->pci = pci;
>> >>       chip->irq = -1;
>> >>       chip->tea575x_tuner = tea575x_tuner;
>> >> -     if ((err = pci_request_regions(pci, "FM801")) < 0) {
>> >> -             kfree(chip);
>> >> -             pci_disable_device(pci);
>> >> +     if ((err = pci_request_regions(pci, "FM801")) < 0)
>> >>               return err;
>> >> -     }
>> >>       chip->port = pci_resource_start(pci, 0);
>> >>       if ((tea575x_tuner & TUNER_ONLY) == 0) {
>> >> -             if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED,
>> >> -                             KBUILD_MODNAME, chip)) {
>> >> -                     dev_err(card->dev, "unable to grab IRQ %d\n", chip->irq);
>> >> +             if (devm_request_irq(&pci->dev, pci->irq, snd_fm801_interrupt,
>> >> +                             IRQF_SHARED, KBUILD_MODNAME, chip)) {
>> >> +                     dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
>> >>                       snd_fm801_free(chip);
>> >>                       return -EBUSY;
>> >>               }
>> >> @@ -1242,12 +1233,6 @@ static int snd_fm801_create(struct snd_card *card,
>> >>       /* init might set tuner access method */
>> >>       tea575x_tuner = chip->tea575x_tuner;
>> >>
>> >> -     if (chip->irq >= 0 && (tea575x_tuner & TUNER_ONLY)) {
>> >> -             pci_clear_master(pci);
>> >> -             free_irq(chip->irq, chip);
>> >> -             chip->irq = -1;
>> >> -     }
>> >> -
>> >>       if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
>> >>               snd_fm801_free(chip);
>> >>               return err;
>> >> --
>> >> 1.8.3.101.g727a46b
>> >>
>>
>>
>>
>> --
>> With Best Regards,
>> Andy Shevchenko
>>
Takashi Iwai Jan. 7, 2015, 1:12 p.m. UTC | #5
At Wed, 7 Jan 2015 14:20:26 +0200,
Andy Shevchenko wrote:
> 
> On Wed, Jan 7, 2015 at 1:27 PM, Takashi Iwai <tiwai@suse.de> wrote:
> > At Wed, 7 Jan 2015 12:54:40 +0200,
> > Andy Shevchenko wrote:
> >>
> >> On Wed, Jan 7, 2015 at 9:11 AM, Takashi Iwai <tiwai@suse.de> wrote:
> >> > At Wed,  7 Jan 2015 01:40:17 +0200,
> >> > Andy Shevchenko wrote:
> >> >>
> >> >> The managed functions allow to get ->probe() and ->remove() simplier.
> >> >> This patch converts code to use managed functions.
> >> >
> >> > This doesn't work well because of the order of release calls in
> >> > device_release().  devres_release_all() is called at first before
> >> > anything else.  Thus the card's free callback would be called after
> >> > it, and snd_fm801_free() touches the hardware before disabling.
> >> >
> >>
> >> Hmm… I didn't get what make those calls. Sound core? The driver is a
> >> normal PCI driver, so resources will be freed *after* ->remove() of
> >> driver was called.
> >> Please, elaborate.
> >
> > Ah, OK, this seems working, as this is the managed *pci* device that
> > is a parent of the card device, thus it shall be released after the
> > children.
> >
> > But any reason not to use pcim_iomap_regions_request_all()?
> 
> Yes. I was doubt to put a comment about this.

Well, pcim_iomap_regions_request_all() can just request regions
without actually iomapping via passing 0 to mask.  But, now looking at
the code again, I couldn't find the place releasing the non-mmio
regions.  Hmm... it might be a leak?

> So, the initial idea is
> to move to MMIO instead of IO access. That's why you may see previous
> patch about fm801_{read,write}w() macros.
> I would like to do that later.

Yeah, of course, rewriting to MMIO would be nicer.  I guess you're
testing with the real hardware, so I'm for this rewrite.


thanks,

Takashi

> 
> >
> >
> > thanks,
> >
> > Takashi
> >
> >>
> >> >
> >> > Takashi
> >> >
> >> >> While here remove the dead code and fix the value printed in error
> >> >> message.
> >> >>
> >> >> Signed-off-by: Andy Shevchenko <andy.shevchenko@gmail.com>
> >> >> ---
> >> >>  sound/pci/fm801.c | 29 +++++++----------------------
> >> >>  1 file changed, 7 insertions(+), 22 deletions(-)
> >> >>
> >> >> diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
> >> >> index dcda3c1..2708500 100644
> >> >> --- a/sound/pci/fm801.c
> >> >> +++ b/sound/pci/fm801.c
> >> >> @@ -1178,12 +1178,8 @@ static int snd_fm801_free(struct fm801 *chip)
> >> >>               v4l2_device_unregister(&chip->v4l2_dev);
> >> >>       }
> >> >>  #endif
> >> >> -     if (chip->irq >= 0)
> >> >> -             free_irq(chip->irq, chip);
> >> >>       pci_release_regions(chip->pci);
> >> >> -     pci_disable_device(chip->pci);
> >> >>
> >> >> -     kfree(chip);
> >> >>       return 0;
> >> >>  }
> >> >>
> >> >> @@ -1206,28 +1202,23 @@ static int snd_fm801_create(struct snd_card *card,
> >> >>       };
> >> >>
> >> >>       *rchip = NULL;
> >> >> -     if ((err = pci_enable_device(pci)) < 0)
> >> >> +     if ((err = pcim_enable_device(pci)) < 0)
> >> >>               return err;
> >> >> -     chip = kzalloc(sizeof(*chip), GFP_KERNEL);
> >> >> -     if (chip == NULL) {
> >> >> -             pci_disable_device(pci);
> >> >> +     chip = devm_kzalloc(&pci->dev, sizeof(*chip), GFP_KERNEL);
> >> >> +     if (chip == NULL)
> >> >>               return -ENOMEM;
> >> >> -     }
> >> >>       spin_lock_init(&chip->reg_lock);
> >> >>       chip->card = card;
> >> >>       chip->pci = pci;
> >> >>       chip->irq = -1;
> >> >>       chip->tea575x_tuner = tea575x_tuner;
> >> >> -     if ((err = pci_request_regions(pci, "FM801")) < 0) {
> >> >> -             kfree(chip);
> >> >> -             pci_disable_device(pci);
> >> >> +     if ((err = pci_request_regions(pci, "FM801")) < 0)
> >> >>               return err;
> >> >> -     }
> >> >>       chip->port = pci_resource_start(pci, 0);
> >> >>       if ((tea575x_tuner & TUNER_ONLY) == 0) {
> >> >> -             if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED,
> >> >> -                             KBUILD_MODNAME, chip)) {
> >> >> -                     dev_err(card->dev, "unable to grab IRQ %d\n", chip->irq);
> >> >> +             if (devm_request_irq(&pci->dev, pci->irq, snd_fm801_interrupt,
> >> >> +                             IRQF_SHARED, KBUILD_MODNAME, chip)) {
> >> >> +                     dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
> >> >>                       snd_fm801_free(chip);
> >> >>                       return -EBUSY;
> >> >>               }
> >> >> @@ -1242,12 +1233,6 @@ static int snd_fm801_create(struct snd_card *card,
> >> >>       /* init might set tuner access method */
> >> >>       tea575x_tuner = chip->tea575x_tuner;
> >> >>
> >> >> -     if (chip->irq >= 0 && (tea575x_tuner & TUNER_ONLY)) {
> >> >> -             pci_clear_master(pci);
> >> >> -             free_irq(chip->irq, chip);
> >> >> -             chip->irq = -1;
> >> >> -     }
> >> >> -
> >> >>       if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
> >> >>               snd_fm801_free(chip);
> >> >>               return err;
> >> >> --
> >> >> 1.8.3.101.g727a46b
> >> >>
> >>
> >>
> >>
> >> --
> >> With Best Regards,
> >> Andy Shevchenko
> >>
> 
> 
> 
> -- 
> With Best Regards,
> Andy Shevchenko
>
Andy Shevchenko Jan. 7, 2015, 1:27 p.m. UTC | #6
On Wed, Jan 7, 2015 at 3:12 PM, Takashi Iwai <tiwai@suse.de> wrote:
> At Wed, 7 Jan 2015 14:20:26 +0200,
> Andy Shevchenko wrote:
>>
>> On Wed, Jan 7, 2015 at 1:27 PM, Takashi Iwai <tiwai@suse.de> wrote:
>> > At Wed, 7 Jan 2015 12:54:40 +0200,
>> > Andy Shevchenko wrote:
>> >>
>> >> On Wed, Jan 7, 2015 at 9:11 AM, Takashi Iwai <tiwai@suse.de> wrote:
>> >> > At Wed,  7 Jan 2015 01:40:17 +0200,
>> >> > Andy Shevchenko wrote:
>> >> >>
>> >> >> The managed functions allow to get ->probe() and ->remove() simplier.
>> >> >> This patch converts code to use managed functions.
>> >> >
>> >> > This doesn't work well because of the order of release calls in
>> >> > device_release().  devres_release_all() is called at first before
>> >> > anything else.  Thus the card's free callback would be called after
>> >> > it, and snd_fm801_free() touches the hardware before disabling.
>> >> >
>> >>
>> >> Hmm… I didn't get what make those calls. Sound core? The driver is a
>> >> normal PCI driver, so resources will be freed *after* ->remove() of
>> >> driver was called.
>> >> Please, elaborate.
>> >
>> > Ah, OK, this seems working, as this is the managed *pci* device that
>> > is a parent of the card device, thus it shall be released after the
>> > children.
>> >
>> > But any reason not to use pcim_iomap_regions_request_all()?
>>
>> Yes. I was doubt to put a comment about this.
>
> Well, pcim_iomap_regions_request_all() can just request regions
> without actually iomapping via passing 0 to mask.  But, now looking at
> the code again, I couldn't find the place releasing the non-mmio
> regions.  Hmm... it might be a leak?

It's in snd_fm801_free().
pci_release_regions(chip->pci);

>
>> So, the initial idea is
>> to move to MMIO instead of IO access. That's why you may see previous
>> patch about fm801_{read,write}w() macros.
>> I would like to do that later.
>
> Yeah, of course, rewriting to MMIO would be nicer.  I guess you're
> testing with the real hardware, so I'm for this rewrite.
>
>
> thanks,
>
> Takashi
>
>>
>> >
>> >
>> > thanks,
>> >
>> > Takashi
>> >
>> >>
>> >> >
>> >> > Takashi
>> >> >
>> >> >> While here remove the dead code and fix the value printed in error
>> >> >> message.
>> >> >>
>> >> >> Signed-off-by: Andy Shevchenko <andy.shevchenko@gmail.com>
>> >> >> ---
>> >> >>  sound/pci/fm801.c | 29 +++++++----------------------
>> >> >>  1 file changed, 7 insertions(+), 22 deletions(-)
>> >> >>
>> >> >> diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
>> >> >> index dcda3c1..2708500 100644
>> >> >> --- a/sound/pci/fm801.c
>> >> >> +++ b/sound/pci/fm801.c
>> >> >> @@ -1178,12 +1178,8 @@ static int snd_fm801_free(struct fm801 *chip)
>> >> >>               v4l2_device_unregister(&chip->v4l2_dev);
>> >> >>       }
>> >> >>  #endif
>> >> >> -     if (chip->irq >= 0)
>> >> >> -             free_irq(chip->irq, chip);
>> >> >>       pci_release_regions(chip->pci);
>> >> >> -     pci_disable_device(chip->pci);
>> >> >>
>> >> >> -     kfree(chip);
>> >> >>       return 0;
>> >> >>  }
>> >> >>
>> >> >> @@ -1206,28 +1202,23 @@ static int snd_fm801_create(struct snd_card *card,
>> >> >>       };
>> >> >>
>> >> >>       *rchip = NULL;
>> >> >> -     if ((err = pci_enable_device(pci)) < 0)
>> >> >> +     if ((err = pcim_enable_device(pci)) < 0)
>> >> >>               return err;
>> >> >> -     chip = kzalloc(sizeof(*chip), GFP_KERNEL);
>> >> >> -     if (chip == NULL) {
>> >> >> -             pci_disable_device(pci);
>> >> >> +     chip = devm_kzalloc(&pci->dev, sizeof(*chip), GFP_KERNEL);
>> >> >> +     if (chip == NULL)
>> >> >>               return -ENOMEM;
>> >> >> -     }
>> >> >>       spin_lock_init(&chip->reg_lock);
>> >> >>       chip->card = card;
>> >> >>       chip->pci = pci;
>> >> >>       chip->irq = -1;
>> >> >>       chip->tea575x_tuner = tea575x_tuner;
>> >> >> -     if ((err = pci_request_regions(pci, "FM801")) < 0) {
>> >> >> -             kfree(chip);
>> >> >> -             pci_disable_device(pci);
>> >> >> +     if ((err = pci_request_regions(pci, "FM801")) < 0)
>> >> >>               return err;
>> >> >> -     }
>> >> >>       chip->port = pci_resource_start(pci, 0);
>> >> >>       if ((tea575x_tuner & TUNER_ONLY) == 0) {
>> >> >> -             if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED,
>> >> >> -                             KBUILD_MODNAME, chip)) {
>> >> >> -                     dev_err(card->dev, "unable to grab IRQ %d\n", chip->irq);
>> >> >> +             if (devm_request_irq(&pci->dev, pci->irq, snd_fm801_interrupt,
>> >> >> +                             IRQF_SHARED, KBUILD_MODNAME, chip)) {
>> >> >> +                     dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
>> >> >>                       snd_fm801_free(chip);
>> >> >>                       return -EBUSY;
>> >> >>               }
>> >> >> @@ -1242,12 +1233,6 @@ static int snd_fm801_create(struct snd_card *card,
>> >> >>       /* init might set tuner access method */
>> >> >>       tea575x_tuner = chip->tea575x_tuner;
>> >> >>
>> >> >> -     if (chip->irq >= 0 && (tea575x_tuner & TUNER_ONLY)) {
>> >> >> -             pci_clear_master(pci);
>> >> >> -             free_irq(chip->irq, chip);
>> >> >> -             chip->irq = -1;
>> >> >> -     }
>> >> >> -
>> >> >>       if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
>> >> >>               snd_fm801_free(chip);
>> >> >>               return err;
>> >> >> --
>> >> >> 1.8.3.101.g727a46b
>> >> >>
>> >>
>> >>
>> >>
>> >> --
>> >> With Best Regards,
>> >> Andy Shevchenko
>> >>
>>
>>
>>
>> --
>> With Best Regards,
>> Andy Shevchenko
>>
Takashi Iwai Jan. 7, 2015, 1:31 p.m. UTC | #7
At Wed, 7 Jan 2015 15:27:35 +0200,
Andy Shevchenko wrote:
> 
> On Wed, Jan 7, 2015 at 3:12 PM, Takashi Iwai <tiwai@suse.de> wrote:
> > At Wed, 7 Jan 2015 14:20:26 +0200,
> > Andy Shevchenko wrote:
> >>
> >> On Wed, Jan 7, 2015 at 1:27 PM, Takashi Iwai <tiwai@suse.de> wrote:
> >> > At Wed, 7 Jan 2015 12:54:40 +0200,
> >> > Andy Shevchenko wrote:
> >> >>
> >> >> On Wed, Jan 7, 2015 at 9:11 AM, Takashi Iwai <tiwai@suse.de> wrote:
> >> >> > At Wed,  7 Jan 2015 01:40:17 +0200,
> >> >> > Andy Shevchenko wrote:
> >> >> >>
> >> >> >> The managed functions allow to get ->probe() and ->remove() simplier.
> >> >> >> This patch converts code to use managed functions.
> >> >> >
> >> >> > This doesn't work well because of the order of release calls in
> >> >> > device_release().  devres_release_all() is called at first before
> >> >> > anything else.  Thus the card's free callback would be called after
> >> >> > it, and snd_fm801_free() touches the hardware before disabling.
> >> >> >
> >> >>
> >> >> Hmm… I didn't get what make those calls. Sound core? The driver is a
> >> >> normal PCI driver, so resources will be freed *after* ->remove() of
> >> >> driver was called.
> >> >> Please, elaborate.
> >> >
> >> > Ah, OK, this seems working, as this is the managed *pci* device that
> >> > is a parent of the card device, thus it shall be released after the
> >> > children.
> >> >
> >> > But any reason not to use pcim_iomap_regions_request_all()?
> >>
> >> Yes. I was doubt to put a comment about this.
> >
> > Well, pcim_iomap_regions_request_all() can just request regions
> > without actually iomapping via passing 0 to mask.  But, now looking at
> > the code again, I couldn't find the place releasing the non-mmio
> > regions.  Hmm... it might be a leak?
> 
> It's in snd_fm801_free().
> pci_release_regions(chip->pci);

I meant the release of regions allocated in
pcim_iomap_regions_request_all().  The function requests all regions,
not only for MMIO ones:

int pcim_iomap_regions_request_all(struct pci_dev *pdev, int mask,
				   const char *name)
{
	int request_mask = ((1 << 6) - 1) & ~mask;
	int rc;

	rc = pci_request_selected_regions(pdev, request_mask, name);
	if (rc)
		return rc;

	rc = pcim_iomap_regions(pdev, mask, name);
	if (rc)
		pci_release_selected_regions(pdev, request_mask);
	return rc;
}

The regions allocated via pcim_iomap_regions() are released via
pcim_iomap_release() properly.  But what about the former one, the
regions allocated via pci_request_selected_regions()...?


Takashi
Andy Shevchenko Jan. 7, 2015, 1:40 p.m. UTC | #8
On Wed, Jan 7, 2015 at 3:31 PM, Takashi Iwai <tiwai@suse.de> wrote:
> At Wed, 7 Jan 2015 15:27:35 +0200,
> Andy Shevchenko wrote:

Regarding to the original patch, is it okay now to apply?

[]

> I meant the release of regions allocated in
> pcim_iomap_regions_request_all().  The function requests all regions,
> not only for MMIO ones:
>
> int pcim_iomap_regions_request_all(struct pci_dev *pdev, int mask,
>                                    const char *name)
> {
>         int request_mask = ((1 << 6) - 1) & ~mask;
>         int rc;
>
>         rc = pci_request_selected_regions(pdev, request_mask, name);
>         if (rc)
>                 return rc;
>
>         rc = pcim_iomap_regions(pdev, mask, name);
>         if (rc)
>                 pci_release_selected_regions(pdev, request_mask);
>         return rc;
> }
>
> The regions allocated via pcim_iomap_regions() are released via
> pcim_iomap_release() properly.  But what about the former one, the
> regions allocated via pci_request_selected_regions()...?

Looks like it requires it's own release function to be implemented, yes.
Good catch.
Takashi Iwai Jan. 7, 2015, 1:43 p.m. UTC | #9
At Wed, 7 Jan 2015 15:40:26 +0200,
Andy Shevchenko wrote:
> 
> On Wed, Jan 7, 2015 at 3:31 PM, Takashi Iwai <tiwai@suse.de> wrote:
> > At Wed, 7 Jan 2015 15:27:35 +0200,
> > Andy Shevchenko wrote:
> 
> Regarding to the original patch, is it okay now to apply?

Yes.  If you prefer, I can apply it first alone.


Takashi
Takashi Iwai Jan. 7, 2015, 1:57 p.m. UTC | #10
At Wed, 07 Jan 2015 14:43:41 +0100,
Takashi Iwai wrote:
> 
> At Wed, 7 Jan 2015 15:40:26 +0200,
> Andy Shevchenko wrote:
> > 
> > On Wed, Jan 7, 2015 at 3:31 PM, Takashi Iwai <tiwai@suse.de> wrote:
> > > At Wed, 7 Jan 2015 15:27:35 +0200,
> > > Andy Shevchenko wrote:
> > 
> > Regarding to the original patch, is it okay now to apply?
> 
> Yes.  If you prefer, I can apply it first alone.

OK, I found that the regions are released in pcim_release().  So,
there is no leak.

Meanwhile it means that pci_release_regions() is superfluous, too,
once when you enabled the managed mode via pcim_enable_device().
Could you resubmit a v2 patch with that removal?


thanks,

Takashi
Andy Shevchenko Jan. 7, 2015, 2:25 p.m. UTC | #11
On Wed, Jan 7, 2015 at 3:57 PM, Takashi Iwai <tiwai@suse.de> wrote:
> At Wed, 07 Jan 2015 14:43:41 +0100,
> Takashi Iwai wrote:
>>
>> At Wed, 7 Jan 2015 15:40:26 +0200,
>> Andy Shevchenko wrote:
>> >
>> > On Wed, Jan 7, 2015 at 3:31 PM, Takashi Iwai <tiwai@suse.de> wrote:
>> > > At Wed, 7 Jan 2015 15:27:35 +0200,
>> > > Andy Shevchenko wrote:
>> >
>> > Regarding to the original patch, is it okay now to apply?
>>
>> Yes.  If you prefer, I can apply it first alone.

Why not? :)

>
> OK, I found that the regions are released in pcim_release().  So,
> there is no leak.
>
> Meanwhile it means that pci_release_regions() is superfluous, too,
> once when you enabled the managed mode via pcim_enable_device().
> Could you resubmit a v2 patch with that removal?

Within few hours together with the second patch. But if you can do
this as a fixup it would be nice.
Takashi Iwai Jan. 7, 2015, 2:59 p.m. UTC | #12
At Wed, 7 Jan 2015 16:25:22 +0200,
Andy Shevchenko wrote:
> 
> On Wed, Jan 7, 2015 at 3:57 PM, Takashi Iwai <tiwai@suse.de> wrote:
> > At Wed, 07 Jan 2015 14:43:41 +0100,
> > Takashi Iwai wrote:
> >>
> >> At Wed, 7 Jan 2015 15:40:26 +0200,
> >> Andy Shevchenko wrote:
> >> >
> >> > On Wed, Jan 7, 2015 at 3:31 PM, Takashi Iwai <tiwai@suse.de> wrote:
> >> > > At Wed, 7 Jan 2015 15:27:35 +0200,
> >> > > Andy Shevchenko wrote:
> >> >
> >> > Regarding to the original patch, is it okay now to apply?
> >>
> >> Yes.  If you prefer, I can apply it first alone.
> 
> Why not? :)
> 
> >
> > OK, I found that the regions are released in pcim_release().  So,
> > there is no leak.
> >
> > Meanwhile it means that pci_release_regions() is superfluous, too,
> > once when you enabled the managed mode via pcim_enable_device().
> > Could you resubmit a v2 patch with that removal?
> 
> Within few hours together with the second patch. But if you can do
> this as a fixup it would be nice.

OK, now applied this patch with a modification (removal of
pci_release_regions()) to for-next branch.


thanks,

Takashi
Takashi Iwai Jan. 20, 2015, 12:42 p.m. UTC | #13
At Wed, 07 Jan 2015 15:59:35 +0100,
Takashi Iwai wrote:
> 
> At Wed, 7 Jan 2015 16:25:22 +0200,
> Andy Shevchenko wrote:
> > 
> > On Wed, Jan 7, 2015 at 3:57 PM, Takashi Iwai <tiwai@suse.de> wrote:
> > > At Wed, 07 Jan 2015 14:43:41 +0100,
> > > Takashi Iwai wrote:
> > >>
> > >> At Wed, 7 Jan 2015 15:40:26 +0200,
> > >> Andy Shevchenko wrote:
> > >> >
> > >> > On Wed, Jan 7, 2015 at 3:31 PM, Takashi Iwai <tiwai@suse.de> wrote:
> > >> > > At Wed, 7 Jan 2015 15:27:35 +0200,
> > >> > > Andy Shevchenko wrote:
> > >> >
> > >> > Regarding to the original patch, is it okay now to apply?
> > >>
> > >> Yes.  If you prefer, I can apply it first alone.
> > 
> > Why not? :)
> > 
> > >
> > > OK, I found that the regions are released in pcim_release().  So,
> > > there is no leak.
> > >
> > > Meanwhile it means that pci_release_regions() is superfluous, too,
> > > once when you enabled the managed mode via pcim_enable_device().
> > > Could you resubmit a v2 patch with that removal?
> > 
> > Within few hours together with the second patch. But if you can do
> > this as a fixup it would be nice.
> 
> OK, now applied this patch with a modification (removal of
> pci_release_regions()) to for-next branch.

I recalled finally why I didn't want this sort of changes.  Namely,
devm_request_irq() can't be used safely for the shared PCI
interrupts.

There is a small open window between the driver's remove call
(i.e. card's private_free or device free calls) and the call of
devres_release_all().  The registered irq handler still remains during
this window.  When an irq is triggered from another shared device
during this, it goes to the remaining irq handler and accesses the
hardware unexpectedly.  In the case of snd_fm801_interrupt(), it's not
too bad, though.


Takashi
Andy Shevchenko Jan. 20, 2015, 1:46 p.m. UTC | #14
On Tue, Jan 20, 2015 at 2:42 PM, Takashi Iwai <tiwai@suse.de> wrote:
> At Wed, 07 Jan 2015 15:59:35 +0100,
> Takashi Iwai wrote:

[]


> I recalled finally why I didn't want this sort of changes.  Namely,
> devm_request_irq() can't be used safely for the shared PCI
> interrupts.
>
> There is a small open window between the driver's remove call
> (i.e. card's private_free or device free calls) and the call of
> devres_release_all().  The registered irq handler still remains during
> this window.  When an irq is triggered from another shared device
> during this, it goes to the remaining irq handler and accesses the
> hardware unexpectedly.  In the case of snd_fm801_interrupt(), it's not
> too bad, though.

Don't we have interrupts disabled on ->remove() stage?
Takashi Iwai Jan. 20, 2015, 1:48 p.m. UTC | #15
At Tue, 20 Jan 2015 15:46:13 +0200,
Andy Shevchenko wrote:
> 
> On Tue, Jan 20, 2015 at 2:42 PM, Takashi Iwai <tiwai@suse.de> wrote:
> > At Wed, 07 Jan 2015 15:59:35 +0100,
> > Takashi Iwai wrote:
> 
> []
> 
> 
> > I recalled finally why I didn't want this sort of changes.  Namely,
> > devm_request_irq() can't be used safely for the shared PCI
> > interrupts.
> >
> > There is a small open window between the driver's remove call
> > (i.e. card's private_free or device free calls) and the call of
> > devres_release_all().  The registered irq handler still remains during
> > this window.  When an irq is triggered from another shared device
> > during this, it goes to the remaining irq handler and accesses the
> > hardware unexpectedly.  In the case of snd_fm801_interrupt(), it's not
> > too bad, though.
> 
> Don't we have interrupts disabled on ->remove() stage?

It's a shared irq, so it doesn't help even if your device disables the
irq.  The other device can trigger the irq line at any time.


Takashi
Andy Shevchenko Jan. 20, 2015, 1:51 p.m. UTC | #16
On Tue, Jan 20, 2015 at 3:48 PM, Takashi Iwai <tiwai@suse.de> wrote:
> At Tue, 20 Jan 2015 15:46:13 +0200,
> Andy Shevchenko wrote:
>>
>> On Tue, Jan 20, 2015 at 2:42 PM, Takashi Iwai <tiwai@suse.de> wrote:
>> > At Wed, 07 Jan 2015 15:59:35 +0100,
>> > Takashi Iwai wrote:
>>
>> []
>>
>>
>> > I recalled finally why I didn't want this sort of changes.  Namely,
>> > devm_request_irq() can't be used safely for the shared PCI
>> > interrupts.
>> >
>> > There is a small open window between the driver's remove call
>> > (i.e. card's private_free or device free calls) and the call of
>> > devres_release_all().  The registered irq handler still remains during
>> > this window.  When an irq is triggered from another shared device
>> > during this, it goes to the remaining irq handler and accesses the
>> > hardware unexpectedly.  In the case of snd_fm801_interrupt(), it's not
>> > too bad, though.
>>
>> Don't we have interrupts disabled on ->remove() stage?
>
> It's a shared irq, so it doesn't help even if your device disables the
> irq.  The other device can trigger the irq line at any time.

Got it. We can call devm_free_irq() explicitly in the ->remove() then.
Takashi Iwai Jan. 20, 2015, 1:56 p.m. UTC | #17
At Tue, 20 Jan 2015 15:51:05 +0200,
Andy Shevchenko wrote:
> 
> On Tue, Jan 20, 2015 at 3:48 PM, Takashi Iwai <tiwai@suse.de> wrote:
> > At Tue, 20 Jan 2015 15:46:13 +0200,
> > Andy Shevchenko wrote:
> >>
> >> On Tue, Jan 20, 2015 at 2:42 PM, Takashi Iwai <tiwai@suse.de> wrote:
> >> > At Wed, 07 Jan 2015 15:59:35 +0100,
> >> > Takashi Iwai wrote:
> >>
> >> []
> >>
> >>
> >> > I recalled finally why I didn't want this sort of changes.  Namely,
> >> > devm_request_irq() can't be used safely for the shared PCI
> >> > interrupts.
> >> >
> >> > There is a small open window between the driver's remove call
> >> > (i.e. card's private_free or device free calls) and the call of
> >> > devres_release_all().  The registered irq handler still remains during
> >> > this window.  When an irq is triggered from another shared device
> >> > during this, it goes to the remaining irq handler and accesses the
> >> > hardware unexpectedly.  In the case of snd_fm801_interrupt(), it's not
> >> > too bad, though.
> >>
> >> Don't we have interrupts disabled on ->remove() stage?
> >
> > It's a shared irq, so it doesn't help even if your device disables the
> > irq.  The other device can trigger the irq line at any time.
> 
> Got it. We can call devm_free_irq() explicitly in the ->remove() then.

Right, but then there is no much merit to use devm_request_irq(), too
:)

As mentioned, in the case of fm801, it's not too bad.  It's just a
single register read, should read zero, and skip the rest.  So we can
live as is.  My point is that we can't take this approach blindly
"just because others do".


Takashi
diff mbox

Patch

diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index dcda3c1..2708500 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -1178,12 +1178,8 @@  static int snd_fm801_free(struct fm801 *chip)
 		v4l2_device_unregister(&chip->v4l2_dev);
 	}
 #endif
-	if (chip->irq >= 0)
-		free_irq(chip->irq, chip);
 	pci_release_regions(chip->pci);
-	pci_disable_device(chip->pci);
 
-	kfree(chip);
 	return 0;
 }
 
@@ -1206,28 +1202,23 @@  static int snd_fm801_create(struct snd_card *card,
 	};
 
 	*rchip = NULL;
-	if ((err = pci_enable_device(pci)) < 0)
+	if ((err = pcim_enable_device(pci)) < 0)
 		return err;
-	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
-	if (chip == NULL) {
-		pci_disable_device(pci);
+	chip = devm_kzalloc(&pci->dev, sizeof(*chip), GFP_KERNEL);
+	if (chip == NULL)
 		return -ENOMEM;
-	}
 	spin_lock_init(&chip->reg_lock);
 	chip->card = card;
 	chip->pci = pci;
 	chip->irq = -1;
 	chip->tea575x_tuner = tea575x_tuner;
-	if ((err = pci_request_regions(pci, "FM801")) < 0) {
-		kfree(chip);
-		pci_disable_device(pci);
+	if ((err = pci_request_regions(pci, "FM801")) < 0)
 		return err;
-	}
 	chip->port = pci_resource_start(pci, 0);
 	if ((tea575x_tuner & TUNER_ONLY) == 0) {
-		if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED,
-				KBUILD_MODNAME, chip)) {
-			dev_err(card->dev, "unable to grab IRQ %d\n", chip->irq);
+		if (devm_request_irq(&pci->dev, pci->irq, snd_fm801_interrupt,
+				IRQF_SHARED, KBUILD_MODNAME, chip)) {
+			dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
 			snd_fm801_free(chip);
 			return -EBUSY;
 		}
@@ -1242,12 +1233,6 @@  static int snd_fm801_create(struct snd_card *card,
 	/* init might set tuner access method */
 	tea575x_tuner = chip->tea575x_tuner;
 
-	if (chip->irq >= 0 && (tea575x_tuner & TUNER_ONLY)) {
-		pci_clear_master(pci);
-		free_irq(chip->irq, chip);
-		chip->irq = -1;
-	}
-
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
 		snd_fm801_free(chip);
 		return err;