Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4985ddbf authored by Takashi Iwai's avatar Takashi Iwai
Browse files

ALSA: intel8x0: Use the new non-cached allocation for 440MX workaround



intel8x0 driver requires the non-cached pages for 440MX workaround,
and this can be implemented more easily with the new memalloc type,
SNDRV_DMA_TYPE_DEV_UC.  This allows us to reduce lots of code.

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 193c7e14
Loading
Loading
Loading
Loading
+12 −77
Original line number Diff line number Diff line
@@ -38,11 +38,6 @@
#include <sound/ac97_codec.h>
#include <sound/info.h>
#include <sound/initval.h>
/* for 440MX workaround */
#include <asm/pgtable.h>
#ifdef CONFIG_X86
#include <asm/set_memory.h>
#endif

MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440; SiS 7012; Ali 5455");
@@ -374,7 +369,6 @@ struct ichdev {
	unsigned int ali_slot;			/* ALI DMA slot */
	struct ac97_pcm *pcm;
	int pcm_open_flag;
	unsigned int page_attr_changed: 1;
	unsigned int suspended: 1;
};

@@ -724,25 +718,6 @@ static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ich
	iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI);
}

#ifdef __i386__
/*
 * Intel 82443MX running a 100MHz processor system bus has a hardware bug,
 * which aborts PCI busmaster for audio transfer.  A workaround is to set
 * the pages as non-cached.  For details, see the errata in
 *	http://download.intel.com/design/chipsets/specupdt/24505108.pdf
 */
static void fill_nocache(void *buf, int size, int nocache)
{
	size = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
	if (nocache)
		set_pages_uc(virt_to_page(buf), size);
	else
		set_pages_wb(virt_to_page(buf), size);
}
#else
#define fill_nocache(buf, size, nocache) do { ; } while (0)
#endif

/*
 *  Interrupt handler
 */
@@ -938,23 +913,12 @@ static int snd_intel8x0_hw_params(struct snd_pcm_substream *substream,
{
	struct intel8x0 *chip = snd_pcm_substream_chip(substream);
	struct ichdev *ichdev = get_ichdev(substream);
	struct snd_pcm_runtime *runtime = substream->runtime;
	int dbl = params_rate(hw_params) > 48000;
	int err;

	if (chip->fix_nocache && ichdev->page_attr_changed) {
		fill_nocache(runtime->dma_area, runtime->dma_bytes, 0); /* clear */
		ichdev->page_attr_changed = 0;
	}
	err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
	if (err < 0)
		return err;
	if (chip->fix_nocache) {
		if (runtime->dma_area && ! ichdev->page_attr_changed) {
			fill_nocache(runtime->dma_area, runtime->dma_bytes, 1);
			ichdev->page_attr_changed = 1;
		}
	}
	if (ichdev->pcm_open_flag) {
		snd_ac97_pcm_close(ichdev->pcm);
		ichdev->pcm_open_flag = 0;
@@ -974,17 +938,12 @@ static int snd_intel8x0_hw_params(struct snd_pcm_substream *substream,

static int snd_intel8x0_hw_free(struct snd_pcm_substream *substream)
{
	struct intel8x0 *chip = snd_pcm_substream_chip(substream);
	struct ichdev *ichdev = get_ichdev(substream);

	if (ichdev->pcm_open_flag) {
		snd_ac97_pcm_close(ichdev->pcm);
		ichdev->pcm_open_flag = 0;
	}
	if (chip->fix_nocache && ichdev->page_attr_changed) {
		fill_nocache(substream->runtime->dma_area, substream->runtime->dma_bytes, 0);
		ichdev->page_attr_changed = 0;
	}
	return snd_pcm_lib_free_pages(substream);
}

@@ -1510,6 +1469,9 @@ struct ich_pcm_table {
	int ac97_idx;
};

#define intel8x0_dma_type(chip) \
	((chip)->fix_nocache ? SNDRV_DMA_TYPE_DEV_UC : SNDRV_DMA_TYPE_DEV)

static int snd_intel8x0_pcm1(struct intel8x0 *chip, int device,
			     struct ich_pcm_table *rec)
{
@@ -1540,7 +1502,7 @@ static int snd_intel8x0_pcm1(struct intel8x0 *chip, int device,
		strcpy(pcm->name, chip->card->shortname);
	chip->pcm[device] = pcm;

	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
	snd_pcm_lib_preallocate_pages_for_all(pcm, intel8x0_dma_type(chip),
					      snd_dma_pci_data(chip->pci),
					      rec->prealloc_size, rec->prealloc_max_size);

@@ -2629,11 +2591,8 @@ static int snd_intel8x0_free(struct intel8x0 *chip)
      __hw_end:
	if (chip->irq >= 0)
		free_irq(chip->irq, chip);
	if (chip->bdbars.area) {
		if (chip->fix_nocache)
			fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 0);
	if (chip->bdbars.area)
		snd_dma_free_pages(&chip->bdbars);
	}
	if (chip->addr)
		pci_iounmap(chip->pci, chip->addr);
	if (chip->bmaddr)
@@ -2657,17 +2616,6 @@ static int intel8x0_suspend(struct device *dev)
	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
	for (i = 0; i < chip->pcm_devs; i++)
		snd_pcm_suspend_all(chip->pcm[i]);
	/* clear nocache */
	if (chip->fix_nocache) {
		for (i = 0; i < chip->bdbars_count; i++) {
			struct ichdev *ichdev = &chip->ichd[i];
			if (ichdev->substream && ichdev->page_attr_changed) {
				struct snd_pcm_runtime *runtime = ichdev->substream->runtime;
				if (runtime->dma_area)
					fill_nocache(runtime->dma_area, runtime->dma_bytes, 0);
			}
		}
	}
	for (i = 0; i < chip->ncodecs; i++)
		snd_ac97_suspend(chip->ac97[i]);
	if (chip->device_type == DEVICE_INTEL_ICH4)
@@ -2708,25 +2656,9 @@ static int intel8x0_resume(struct device *dev)
			  ICH_PCM_SPDIF_1011);
	}

	/* refill nocache */
	if (chip->fix_nocache)
		fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 1);

	for (i = 0; i < chip->ncodecs; i++)
		snd_ac97_resume(chip->ac97[i]);

	/* refill nocache */
	if (chip->fix_nocache) {
		for (i = 0; i < chip->bdbars_count; i++) {
			struct ichdev *ichdev = &chip->ichd[i];
			if (ichdev->substream && ichdev->page_attr_changed) {
				struct snd_pcm_runtime *runtime = ichdev->substream->runtime;
				if (runtime->dma_area)
					fill_nocache(runtime->dma_area, runtime->dma_bytes, 1);
			}
		}
	}

	/* resume status */
	for (i = 0; i < chip->bdbars_count; i++) {
		struct ichdev *ichdev = &chip->ichd[i];
@@ -3057,6 +2989,12 @@ static int snd_intel8x0_create(struct snd_card *card,

	chip->inside_vm = snd_intel8x0_inside_vm(pci);

	/*
	 * Intel 82443MX running a 100MHz processor system bus has a hardware
	 * bug, which aborts PCI busmaster for audio transfer.  A workaround
	 * is to set the pages as non-cached.  For details, see the errata in
	 *     http://download.intel.com/design/chipsets/specupdt/24505108.pdf
	 */
	if (pci->vendor == PCI_VENDOR_ID_INTEL &&
	    pci->device == PCI_DEVICE_ID_INTEL_440MX)
		chip->fix_nocache = 1; /* enable workaround */
@@ -3128,7 +3066,7 @@ 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(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
	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);
@@ -3137,9 +3075,6 @@ static int snd_intel8x0_create(struct snd_card *card,
	}
	/* tables must be aligned to 8 bytes here, but the kernel pages
	   are much bigger, so we don't care (on i386) */
	/* workaround for 440MX */
	if (chip->fix_nocache)
		fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 1);
	int_sta_masks = 0;
	for (i = 0; i < chip->bdbars_count; i++) {
		ichdev = &chip->ichd[i];