From 0110876eec8d735be4ee8870a151c128a0158e07 Mon Sep 17 00:00:00 2001 From: marius Date: Tue, 22 Sep 2009 11:38:45 +0000 Subject: [PATCH] - According to Linux, the ALi M5451 can do 31-bit DMA instead of just 30-bit like the reset of the controllers supported by this driver. Actually ALi M5451 can be setup up to generate 32-bit addresses by setting the 31st bit via the accompanying ISA bridge, which allows it to work in sparc64 machines whose IOMMU require at least 32-bit DMA. Even though other architectures would also benefit from 32-bit DMA, enabling this bit is limited to sparc64 as bus_dma(9) doesn't generally guarantee that a low address of BUS_SPACE_MAXADDR_32BIT results in a buffer in the 32-bit range. - According to Tatsuo YOKOGAWA's ali(4), the the DMA transfer size of ALi M5451 is fixed to 64k and in fact using the default size of 4k - The 4DWAVE DX and NX require the recording buffer to be 8-byte aligned so adjust the bus_dma_tag_create(9) accordingly. - Unlike the rest of the controllers supported by this driver, the ALi M5451 only has 32 hardware channels instead of 64 so limit the loop in tr_intr() accordingly. [1] Submitted by: yongari [1] Reviewed by: yongari (superset of what is committed) MFC after: 3 days --- sys/dev/sound/pci/t4dwave.c | 96 ++++++++++++++++++++++++++++++------- 1 file changed, 78 insertions(+), 18 deletions(-) diff --git a/sys/dev/sound/pci/t4dwave.c b/sys/dev/sound/pci/t4dwave.c index 086c4fe9227a..8d9c4c64e9a7 100644 --- a/sys/dev/sound/pci/t4dwave.c +++ b/sys/dev/sound/pci/t4dwave.c @@ -45,18 +45,22 @@ SND_DECLARE_FILE("$FreeBSD$"); #define SPA_PCI_ID 0x70181039 #define TR_DEFAULT_BUFSZ 0x1000 +/* For ALi M5451 the DMA transfer size appears to be fixed to 64k. */ +#define ALI_BUFSZ 0x10000 +#define TR_BUFALGN 0x8 #define TR_TIMEOUT_CDC 0xffff +#define TR_MAXHWCH 64 +#define ALI_MAXHWCH 32 #define TR_MAXPLAYCH 4 +#define ALI_MAXPLAYCH 1 /* - * Though, it's not clearly documented in trident datasheet, trident - * audio cards can't handle DMA addresses located above 1GB. The LBA - * (loop begin address) register which holds DMA base address is 32bits - * register. - * But the MSB 2bits are used for other purposes(I guess it is really - * bad idea). This effectivly limits the DMA address space up to 1GB. + * Though, it's not clearly documented in the 4DWAVE datasheet, the + * DX and NX chips can't handle DMA addresses located above 1GB as the + * LBA (loop begin address) register which holds the DMA base address + * is 32-bit, but the two MSBs are used for other purposes. */ -#define TR_MAXADDR ((1 << 30) - 1) - +#define TR_MAXADDR ((1U << 30) - 1) +#define ALI_MAXADDR ((1U << 31) - 1) struct tr_info; @@ -97,6 +101,7 @@ struct tr_info { struct mtx *lock; + u_int32_t hwchns; u_int32_t playchns; unsigned int bufsz; @@ -398,7 +403,10 @@ tr_wrch(struct tr_chinfo *ch) ch->ec &= 0x00000fff; ch->alpha &= 0x00000fff; ch->delta &= 0x0000ffff; - ch->lba &= 0x3fffffff; + if (tr->type == ALI_PCI_ID) + ch->lba &= ALI_MAXADDR; + else + ch->lba &= TR_MAXADDR; cr[1]=ch->lba; cr[3]=(ch->fmc<<14) | (ch->rvol<<7) | (ch->cvol); @@ -441,7 +449,10 @@ tr_rdch(struct tr_chinfo *ch) snd_mtxunlock(tr->lock); - ch->lba= (cr[1] & 0x3fffffff); + if (tr->type == ALI_PCI_ID) + ch->lba=(cr[1] & ALI_MAXADDR); + else + ch->lba=(cr[1] & TR_MAXADDR); ch->fmc= (cr[3] & 0x0000c000) >> 14; ch->rvol= (cr[3] & 0x00003f80) >> 7; ch->cvol= (cr[3] & 0x0000007f); @@ -628,7 +639,6 @@ trrchan_setformat(kobj_t obj, void *data, u_int32_t format) tr_wr(tr, TR_REG_SBCTRL, i, 1); return 0; - } static u_int32_t @@ -729,7 +739,7 @@ tr_intr(void *p) intsrc = tr_rd(tr, TR_REG_MISCINT, 4); if (intsrc & TR_INT_ADDR) { chnum = 0; - while (chnum < 64) { + while (chnum < tr->hwchns) { mask = 0x00000001; active = tr_rd(tr, (chnum < 32)? TR_REG_ADDRINTA : TR_REG_ADDRINTB, 4); bufhalf = tr_rd(tr, (chnum < 32)? TR_REG_CSPF_A : TR_REG_CSPF_B, 4); @@ -815,8 +825,13 @@ tr_pci_attach(device_t dev) u_int32_t data; struct tr_info *tr; struct ac97_info *codec = 0; + bus_addr_t lowaddr; int i, dacn; char status[SND_STATUSLEN]; +#ifdef __sparc64__ + device_t *children; + int nchildren; +#endif tr = malloc(sizeof(*tr), M_DEVBUF, M_WAITOK | M_ZERO); tr->type = pci_get_devid(dev); @@ -834,7 +849,7 @@ tr_pci_attach(device_t dev) } else { switch (tr->type) { case ALI_PCI_ID: - dacn = 1; + dacn = ALI_MAXPLAYCH; break; default: dacn = TR_MAXPLAYCH; @@ -859,8 +874,6 @@ tr_pci_attach(device_t dev) goto bad; } - tr->bufsz = pcm_getbuffersize(dev, 4096, TR_DEFAULT_BUFSZ, 65536); - if (tr_init(tr) == -1) { device_printf(dev, "unable to initialize the card\n"); goto bad; @@ -879,12 +892,59 @@ tr_pci_attach(device_t dev) goto bad; } - if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2, + if (tr->type == ALI_PCI_ID) { + /* + * The M5451 generates 31 bit of DMA and in order to do + * 32-bit DMA, the 31st bit can be set via its accompanying + * ISA bridge. Note that we can't predict whether bus_dma(9) + * will actually supply us with a 32-bit buffer and even when + * using a low address of BUS_SPACE_MAXADDR_32BIT for both + * we might end up with the play buffer being in the 32-bit + * range while the record buffer isn't or vice versa. So we + * limit enabling the 31st bit to sparc64, where the IOMMU + * guarantees that we're using a 32-bit address (and in turn + * requires it). + */ + lowaddr = ALI_MAXADDR; +#ifdef __sparc64__ + if (device_get_children(device_get_parent(dev), &children, + &nchildren) == 0) { + for (i = 0; i < nchildren; i++) { + if (pci_get_devid(children[i]) == 0x153310b9) { + lowaddr = BUS_SPACE_MAXADDR_32BIT; + data = pci_read_config(children[i], + 0x7e, 1); + if (bootverbose) + device_printf(dev, + "M1533 0x7e: 0x%x -> ", + data); + data |= 0x1; + if (bootverbose) + printf("0x%x\n", data); + pci_write_config(children[i], 0x7e, + data, 1); + break; + } + } + } + free(children, M_TEMP); +#endif + tr->hwchns = ALI_MAXHWCH; + tr->bufsz = ALI_BUFSZ; + } else { + lowaddr = TR_MAXADDR; + tr->hwchns = TR_MAXHWCH; + tr->bufsz = pcm_getbuffersize(dev, 4096, TR_DEFAULT_BUFSZ, + 65536); + } + + if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), + /*alignment*/TR_BUFALGN, /*boundary*/0, - /*lowaddr*/TR_MAXADDR, + /*lowaddr*/lowaddr, /*highaddr*/BUS_SPACE_MAXADDR, /*filter*/NULL, /*filterarg*/NULL, - /*maxsize*/tr->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff, + /*maxsize*/tr->bufsz, /*nsegments*/1, /*maxsegz*/tr->bufsz, /*flags*/0, /*lockfunc*/busdma_lock_mutex, /*lockarg*/&Giant, &tr->parent_dmat) != 0) { device_printf(dev, "unable to create dma tag\n");