Loading sound/pci/hda/hda_intel.c +71 −43 Original line number Diff line number Diff line Loading @@ -206,8 +206,9 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define MAX_AZX_DEV 16 /* max number of fragments - we may use more if allocating more pages for BDL */ #define BDL_SIZE PAGE_ALIGN(8192) #define AZX_MAX_FRAG (BDL_SIZE / (MAX_AZX_DEV * 16)) #define BDL_SIZE 4096 #define AZX_MAX_BDL_ENTRIES (BDL_SIZE / 16) #define AZX_MAX_FRAG 32 /* max buffer size - no h/w limit, you can increase as you like */ #define AZX_MAX_BUF_SIZE (1024*1024*1024) /* max number of PCM devics per card */ Loading Loading @@ -282,12 +283,10 @@ enum { */ struct azx_dev { u32 *bdl; /* virtual address of the BDL */ dma_addr_t bdl_addr; /* physical address of the BDL */ struct snd_dma_buffer bdl; /* BDL buffer */ u32 *posbuf; /* position buffer pointer */ unsigned int bufsize; /* size of the play buffer in bytes */ unsigned int fragsize; /* size of each period in bytes */ unsigned int frags; /* number for period in the play buffer */ unsigned int fifo_size; /* FIFO size */ Loading Loading @@ -358,8 +357,7 @@ struct azx { struct azx_rb corb; struct azx_rb rirb; /* BDL, CORB/RIRB and position buffers */ struct snd_dma_buffer bdl; /* CORB/RIRB and position buffers */ struct snd_dma_buffer rb; struct snd_dma_buffer posbuf; Loading Loading @@ -962,30 +960,57 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) /* * set up BDL entries */ static void azx_setup_periods(struct azx_dev *azx_dev) static int azx_setup_periods(struct snd_pcm_substream *substream, struct azx_dev *azx_dev) { u32 *bdl = azx_dev->bdl; dma_addr_t dma_addr = azx_dev->substream->runtime->dma_addr; int idx; struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream); u32 *bdl; int i, ofs, periods, period_bytes; /* reset BDL address */ azx_sd_writel(azx_dev, SD_BDLPL, 0); azx_sd_writel(azx_dev, SD_BDLPU, 0); period_bytes = snd_pcm_lib_period_bytes(substream); periods = azx_dev->bufsize / period_bytes; /* program the initial BDL entries */ for (idx = 0; idx < azx_dev->frags; idx++) { unsigned int off = idx << 2; /* 4 dword step */ dma_addr_t addr = dma_addr + idx * azx_dev->fragsize; bdl = (u32 *)azx_dev->bdl.area; ofs = 0; azx_dev->frags = 0; for (i = 0; i < periods; i++) { int size, rest; if (i >= AZX_MAX_BDL_ENTRIES) { snd_printk(KERN_ERR "Too many BDL entries: " "buffer=%d, period=%d\n", azx_dev->bufsize, period_bytes); /* reset */ azx_sd_writel(azx_dev, SD_BDLPL, 0); azx_sd_writel(azx_dev, SD_BDLPU, 0); return -EINVAL; } rest = period_bytes; do { dma_addr_t addr = snd_pcm_sgbuf_get_addr(sgbuf, ofs); /* program the address field of the BDL entry */ bdl[off] = cpu_to_le32((u32)addr); bdl[off+1] = cpu_to_le32(upper_32bit(addr)); bdl[0] = cpu_to_le32((u32)addr); bdl[1] = cpu_to_le32(upper_32bit(addr)); /* program the size field of the BDL entry */ bdl[off+2] = cpu_to_le32(azx_dev->fragsize); /* program the IOC to enable interrupt when buffer completes */ bdl[off+3] = cpu_to_le32(0x01); size = PAGE_SIZE - (ofs % PAGE_SIZE); if (rest < size) size = rest; bdl[2] = cpu_to_le32(size); /* program the IOC to enable interrupt * only when the whole fragment is processed */ rest -= size; bdl[3] = rest ? 0 : cpu_to_le32(0x01); bdl += 4; azx_dev->frags++; ofs += size; } while (rest > 0); } return 0; } /* Loading Loading @@ -1034,9 +1059,9 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) /* program the BDL address */ /* lower BDL address */ azx_sd_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl_addr); azx_sd_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr); /* upper BDL address */ azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr)); azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl.addr)); /* enable the position buffer */ if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) Loading Loading @@ -1272,8 +1297,6 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; azx_dev->bufsize = snd_pcm_lib_buffer_bytes(substream); azx_dev->fragsize = snd_pcm_lib_period_bytes(substream); azx_dev->frags = azx_dev->bufsize / azx_dev->fragsize; azx_dev->format_val = snd_hda_calc_stream_format(runtime->rate, runtime->channels, runtime->format, Loading @@ -1288,7 +1311,8 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) snd_printdd("azx_pcm_prepare: bufsize=0x%x, fragsize=0x%x, " "format=0x%x\n", azx_dev->bufsize, azx_dev->fragsize, azx_dev->format_val); azx_setup_periods(azx_dev); if (azx_setup_periods(substream, azx_dev) < 0) return -EINVAL; azx_setup_controller(chip, azx_dev); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1; Loading Loading @@ -1375,6 +1399,7 @@ static struct snd_pcm_ops azx_pcm_ops = { .prepare = azx_pcm_prepare, .trigger = azx_pcm_trigger, .pointer = azx_pcm_pointer, .page = snd_pcm_sgbuf_ops_page, }; static void azx_pcm_free(struct snd_pcm *pcm) Loading Loading @@ -1417,7 +1442,7 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec, snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &azx_pcm_ops); if (cpcm->stream[1].substreams) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(chip->pci), 1024 * 64, 1024 * 1024); chip->pcm[cpcm->device] = pcm; Loading Loading @@ -1507,10 +1532,7 @@ static int __devinit azx_init_stream(struct azx *chip) * and initialize */ for (i = 0; i < chip->num_streams; i++) { unsigned int off = sizeof(u32) * (i * AZX_MAX_FRAG * 4); struct azx_dev *azx_dev = &chip->azx_dev[i]; azx_dev->bdl = (u32 *)(chip->bdl.area + off); azx_dev->bdl_addr = chip->bdl.addr + off; azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8); /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); Loading Loading @@ -1646,8 +1668,9 @@ static int azx_resume(struct pci_dev *pci) */ static int azx_free(struct azx *chip) { if (chip->initialized) { int i; if (chip->initialized) { for (i = 0; i < chip->num_streams; i++) azx_stream_stop(chip, &chip->azx_dev[i]); azx_stop_chip(chip); Loading @@ -1662,8 +1685,11 @@ static int azx_free(struct azx *chip) if (chip->remap_addr) iounmap(chip->remap_addr); if (chip->bdl.area) snd_dma_free_pages(&chip->bdl); if (chip->azx_dev) { for (i = 0; i < chip->num_streams; i++) if (chip->azx_dev[i].bdl.area) snd_dma_free_pages(&chip->azx_dev[i].bdl); } if (chip->rb.area) snd_dma_free_pages(&chip->rb); if (chip->posbuf.area) Loading Loading @@ -1745,7 +1771,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, struct azx **rchip) { struct azx *chip; int err; int i, err; unsigned short gcap; static struct snd_device_ops ops = { .dev_free = azx_dev_free, Loading Loading @@ -1857,14 +1883,16 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, goto errout; } for (i = 0; i < chip->num_streams; i++) { /* allocate memory for the BDL for each stream */ err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), BDL_SIZE, &chip->bdl); BDL_SIZE, &chip->azx_dev[i].bdl); if (err < 0) { snd_printk(KERN_ERR SFX "cannot allocate BDL\n"); goto errout; } } /* allocate memory for the position buffer */ err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), Loading Loading
sound/pci/hda/hda_intel.c +71 −43 Original line number Diff line number Diff line Loading @@ -206,8 +206,9 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define MAX_AZX_DEV 16 /* max number of fragments - we may use more if allocating more pages for BDL */ #define BDL_SIZE PAGE_ALIGN(8192) #define AZX_MAX_FRAG (BDL_SIZE / (MAX_AZX_DEV * 16)) #define BDL_SIZE 4096 #define AZX_MAX_BDL_ENTRIES (BDL_SIZE / 16) #define AZX_MAX_FRAG 32 /* max buffer size - no h/w limit, you can increase as you like */ #define AZX_MAX_BUF_SIZE (1024*1024*1024) /* max number of PCM devics per card */ Loading Loading @@ -282,12 +283,10 @@ enum { */ struct azx_dev { u32 *bdl; /* virtual address of the BDL */ dma_addr_t bdl_addr; /* physical address of the BDL */ struct snd_dma_buffer bdl; /* BDL buffer */ u32 *posbuf; /* position buffer pointer */ unsigned int bufsize; /* size of the play buffer in bytes */ unsigned int fragsize; /* size of each period in bytes */ unsigned int frags; /* number for period in the play buffer */ unsigned int fifo_size; /* FIFO size */ Loading Loading @@ -358,8 +357,7 @@ struct azx { struct azx_rb corb; struct azx_rb rirb; /* BDL, CORB/RIRB and position buffers */ struct snd_dma_buffer bdl; /* CORB/RIRB and position buffers */ struct snd_dma_buffer rb; struct snd_dma_buffer posbuf; Loading Loading @@ -962,30 +960,57 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) /* * set up BDL entries */ static void azx_setup_periods(struct azx_dev *azx_dev) static int azx_setup_periods(struct snd_pcm_substream *substream, struct azx_dev *azx_dev) { u32 *bdl = azx_dev->bdl; dma_addr_t dma_addr = azx_dev->substream->runtime->dma_addr; int idx; struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream); u32 *bdl; int i, ofs, periods, period_bytes; /* reset BDL address */ azx_sd_writel(azx_dev, SD_BDLPL, 0); azx_sd_writel(azx_dev, SD_BDLPU, 0); period_bytes = snd_pcm_lib_period_bytes(substream); periods = azx_dev->bufsize / period_bytes; /* program the initial BDL entries */ for (idx = 0; idx < azx_dev->frags; idx++) { unsigned int off = idx << 2; /* 4 dword step */ dma_addr_t addr = dma_addr + idx * azx_dev->fragsize; bdl = (u32 *)azx_dev->bdl.area; ofs = 0; azx_dev->frags = 0; for (i = 0; i < periods; i++) { int size, rest; if (i >= AZX_MAX_BDL_ENTRIES) { snd_printk(KERN_ERR "Too many BDL entries: " "buffer=%d, period=%d\n", azx_dev->bufsize, period_bytes); /* reset */ azx_sd_writel(azx_dev, SD_BDLPL, 0); azx_sd_writel(azx_dev, SD_BDLPU, 0); return -EINVAL; } rest = period_bytes; do { dma_addr_t addr = snd_pcm_sgbuf_get_addr(sgbuf, ofs); /* program the address field of the BDL entry */ bdl[off] = cpu_to_le32((u32)addr); bdl[off+1] = cpu_to_le32(upper_32bit(addr)); bdl[0] = cpu_to_le32((u32)addr); bdl[1] = cpu_to_le32(upper_32bit(addr)); /* program the size field of the BDL entry */ bdl[off+2] = cpu_to_le32(azx_dev->fragsize); /* program the IOC to enable interrupt when buffer completes */ bdl[off+3] = cpu_to_le32(0x01); size = PAGE_SIZE - (ofs % PAGE_SIZE); if (rest < size) size = rest; bdl[2] = cpu_to_le32(size); /* program the IOC to enable interrupt * only when the whole fragment is processed */ rest -= size; bdl[3] = rest ? 0 : cpu_to_le32(0x01); bdl += 4; azx_dev->frags++; ofs += size; } while (rest > 0); } return 0; } /* Loading Loading @@ -1034,9 +1059,9 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) /* program the BDL address */ /* lower BDL address */ azx_sd_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl_addr); azx_sd_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr); /* upper BDL address */ azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr)); azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl.addr)); /* enable the position buffer */ if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) Loading Loading @@ -1272,8 +1297,6 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; azx_dev->bufsize = snd_pcm_lib_buffer_bytes(substream); azx_dev->fragsize = snd_pcm_lib_period_bytes(substream); azx_dev->frags = azx_dev->bufsize / azx_dev->fragsize; azx_dev->format_val = snd_hda_calc_stream_format(runtime->rate, runtime->channels, runtime->format, Loading @@ -1288,7 +1311,8 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) snd_printdd("azx_pcm_prepare: bufsize=0x%x, fragsize=0x%x, " "format=0x%x\n", azx_dev->bufsize, azx_dev->fragsize, azx_dev->format_val); azx_setup_periods(azx_dev); if (azx_setup_periods(substream, azx_dev) < 0) return -EINVAL; azx_setup_controller(chip, azx_dev); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1; Loading Loading @@ -1375,6 +1399,7 @@ static struct snd_pcm_ops azx_pcm_ops = { .prepare = azx_pcm_prepare, .trigger = azx_pcm_trigger, .pointer = azx_pcm_pointer, .page = snd_pcm_sgbuf_ops_page, }; static void azx_pcm_free(struct snd_pcm *pcm) Loading Loading @@ -1417,7 +1442,7 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec, snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &azx_pcm_ops); if (cpcm->stream[1].substreams) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(chip->pci), 1024 * 64, 1024 * 1024); chip->pcm[cpcm->device] = pcm; Loading Loading @@ -1507,10 +1532,7 @@ static int __devinit azx_init_stream(struct azx *chip) * and initialize */ for (i = 0; i < chip->num_streams; i++) { unsigned int off = sizeof(u32) * (i * AZX_MAX_FRAG * 4); struct azx_dev *azx_dev = &chip->azx_dev[i]; azx_dev->bdl = (u32 *)(chip->bdl.area + off); azx_dev->bdl_addr = chip->bdl.addr + off; azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8); /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); Loading Loading @@ -1646,8 +1668,9 @@ static int azx_resume(struct pci_dev *pci) */ static int azx_free(struct azx *chip) { if (chip->initialized) { int i; if (chip->initialized) { for (i = 0; i < chip->num_streams; i++) azx_stream_stop(chip, &chip->azx_dev[i]); azx_stop_chip(chip); Loading @@ -1662,8 +1685,11 @@ static int azx_free(struct azx *chip) if (chip->remap_addr) iounmap(chip->remap_addr); if (chip->bdl.area) snd_dma_free_pages(&chip->bdl); if (chip->azx_dev) { for (i = 0; i < chip->num_streams; i++) if (chip->azx_dev[i].bdl.area) snd_dma_free_pages(&chip->azx_dev[i].bdl); } if (chip->rb.area) snd_dma_free_pages(&chip->rb); if (chip->posbuf.area) Loading Loading @@ -1745,7 +1771,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, struct azx **rchip) { struct azx *chip; int err; int i, err; unsigned short gcap; static struct snd_device_ops ops = { .dev_free = azx_dev_free, Loading Loading @@ -1857,14 +1883,16 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, goto errout; } for (i = 0; i < chip->num_streams; i++) { /* allocate memory for the BDL for each stream */ err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), BDL_SIZE, &chip->bdl); BDL_SIZE, &chip->azx_dev[i].bdl); if (err < 0) { snd_printk(KERN_ERR SFX "cannot allocate BDL\n"); goto errout; } } /* allocate memory for the position buffer */ err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), Loading