From 46ecd12c07f921bb015f87cb07ddb02baa94b382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Fonseca?= Date: Wed, 5 Dec 2007 00:10:39 +0000 Subject: mach64: use utf-8 --- shared-core/mach64_dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-core/mach64_dma.c') diff --git a/shared-core/mach64_dma.c b/shared-core/mach64_dma.c index 13fa0446..dd3547f8 100644 --- a/shared-core/mach64_dma.c +++ b/shared-core/mach64_dma.c @@ -6,7 +6,7 @@ * \author Gareth Hughes * \author Frank C. Earl * \author Leif Delgass - * \author Jose Fonseca + * \author José Fonseca */ /* -- cgit v1.2.3 From a64a4373e85a321a359e147b2c7220d501dff06a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Fonseca?= Date: Wed, 5 Dec 2007 22:53:02 +0000 Subject: mach64: make buffer emission macros normal functions --- shared-core/mach64_dma.c | 227 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) (limited to 'shared-core/mach64_dma.c') diff --git a/shared-core/mach64_dma.c b/shared-core/mach64_dma.c index dd3547f8..9aa3f768 100644 --- a/shared-core/mach64_dma.c +++ b/shared-core/mach64_dma.c @@ -558,6 +558,233 @@ void mach64_dump_ring_info(drm_mach64_private_t * dev_priv) /*@}*/ +/*******************************************************************/ +/** \name DMA descriptor ring macros */ +/*@{*/ + +static __inline__ void mach64_set_dma_eol(volatile u32 * addr) +{ +#if defined(__i386__) + int nr = 31; + + /* Taken from include/asm-i386/bitops.h linux header */ + __asm__ __volatile__("lock;" "btsl %1,%0":"=m"(*addr) + :"Ir"(nr)); +#elif defined(__powerpc__) + u32 old; + u32 mask = cpu_to_le32(MACH64_DMA_EOL); + + /* Taken from the include/asm-ppc/bitops.h linux header */ + __asm__ __volatile__("\n\ +1: lwarx %0,0,%3 \n\ + or %0,%0,%2 \n\ + stwcx. %0,0,%3 \n\ + bne- 1b":"=&r"(old), "=m"(*addr) + :"r"(mask), "r"(addr), "m"(*addr) + :"cc"); +#elif defined(__alpha__) + u32 temp; + u32 mask = MACH64_DMA_EOL; + + /* Taken from the include/asm-alpha/bitops.h linux header */ + __asm__ __volatile__("1: ldl_l %0,%3\n" + " bis %0,%2,%0\n" + " stl_c %0,%1\n" + " beq %0,2f\n" + ".subsection 2\n" + "2: br 1b\n" + ".previous":"=&r"(temp), "=m"(*addr) + :"Ir"(mask), "m"(*addr)); +#else + u32 mask = cpu_to_le32(MACH64_DMA_EOL); + + *addr |= mask; +#endif +} + +static __inline__ void mach64_clear_dma_eol(volatile u32 * addr) +{ +#if defined(__i386__) + int nr = 31; + + /* Taken from include/asm-i386/bitops.h linux header */ + __asm__ __volatile__("lock;" "btrl %1,%0":"=m"(*addr) + :"Ir"(nr)); +#elif defined(__powerpc__) + u32 old; + u32 mask = cpu_to_le32(MACH64_DMA_EOL); + + /* Taken from the include/asm-ppc/bitops.h linux header */ + __asm__ __volatile__("\n\ +1: lwarx %0,0,%3 \n\ + andc %0,%0,%2 \n\ + stwcx. %0,0,%3 \n\ + bne- 1b":"=&r"(old), "=m"(*addr) + :"r"(mask), "r"(addr), "m"(*addr) + :"cc"); +#elif defined(__alpha__) + u32 temp; + u32 mask = ~MACH64_DMA_EOL; + + /* Taken from the include/asm-alpha/bitops.h linux header */ + __asm__ __volatile__("1: ldl_l %0,%3\n" + " and %0,%2,%0\n" + " stl_c %0,%1\n" + " beq %0,2f\n" + ".subsection 2\n" + "2: br 1b\n" + ".previous":"=&r"(temp), "=m"(*addr) + :"Ir"(mask), "m"(*addr)); +#else + u32 mask = cpu_to_le32(~MACH64_DMA_EOL); + + *addr &= mask; +#endif +} + +#define RING_LOCALS \ + int _ring_tail, _ring_write; unsigned int _ring_mask; volatile u32 *_ring + +#define RING_WRITE_OFS _ring_write + +#define BEGIN_RING( n ) \ +do { \ + if ( MACH64_VERBOSE ) { \ + DRM_INFO( "BEGIN_RING( %d ) in %s\n", \ + (n), __FUNCTION__ ); \ + } \ + if ( dev_priv->ring.space <= (n) * sizeof(u32) ) { \ + int ret; \ + if ((ret=mach64_wait_ring( dev_priv, (n) * sizeof(u32))) < 0 ) { \ + DRM_ERROR( "wait_ring failed, resetting engine\n"); \ + mach64_dump_engine_info( dev_priv ); \ + mach64_do_engine_reset( dev_priv ); \ + return ret; \ + } \ + } \ + dev_priv->ring.space -= (n) * sizeof(u32); \ + _ring = (u32 *) dev_priv->ring.start; \ + _ring_tail = _ring_write = dev_priv->ring.tail; \ + _ring_mask = dev_priv->ring.tail_mask; \ +} while (0) + +#define OUT_RING( x ) \ +do { \ + if ( MACH64_VERBOSE ) { \ + DRM_INFO( " OUT_RING( 0x%08x ) at 0x%x\n", \ + (unsigned int)(x), _ring_write ); \ + } \ + _ring[_ring_write++] = cpu_to_le32( x ); \ + _ring_write &= _ring_mask; \ +} while (0) + +#define ADVANCE_RING() \ +do { \ + if ( MACH64_VERBOSE ) { \ + DRM_INFO( "ADVANCE_RING() wr=0x%06x tail=0x%06x\n", \ + _ring_write, _ring_tail ); \ + } \ + DRM_MEMORYBARRIER(); \ + mach64_clear_dma_eol( &_ring[(_ring_tail - 2) & _ring_mask] ); \ + DRM_MEMORYBARRIER(); \ + dev_priv->ring.tail = _ring_write; \ + mach64_ring_tick( dev_priv, &(dev_priv)->ring ); \ +} while (0) + + +int mach64_add_buf_to_ring(drm_mach64_private_t *dev_priv, + drm_mach64_freelist_t *entry) +{ + int bytes, pages, remainder; + u32 address, page; + int i; + struct drm_buf *buf = entry->buf; + RING_LOCALS; + + bytes = buf->used; + address = GETBUFADDR( buf ); + pages = (bytes + MACH64_DMA_CHUNKSIZE - 1) / MACH64_DMA_CHUNKSIZE; + + BEGIN_RING( pages * 4 ); + + for ( i = 0 ; i < pages-1 ; i++ ) { + page = address + i * MACH64_DMA_CHUNKSIZE; + OUT_RING( MACH64_APERTURE_OFFSET + MACH64_BM_ADDR ); + OUT_RING( page ); + OUT_RING( MACH64_DMA_CHUNKSIZE | MACH64_DMA_HOLD_OFFSET ); + OUT_RING( 0 ); + } + + /* generate the final descriptor for any remaining commands in this buffer */ + page = address + i * MACH64_DMA_CHUNKSIZE; + remainder = bytes - i * MACH64_DMA_CHUNKSIZE; + + /* Save dword offset of last descriptor for this buffer. + * This is needed to check for completion of the buffer in freelist_get + */ + entry->ring_ofs = RING_WRITE_OFS; + + OUT_RING( MACH64_APERTURE_OFFSET + MACH64_BM_ADDR ); + OUT_RING( page ); + OUT_RING( remainder | MACH64_DMA_HOLD_OFFSET | MACH64_DMA_EOL ); + OUT_RING( 0 ); + + ADVANCE_RING(); + + return 0; +} + +int mach64_add_hostdata_buf_to_ring(drm_mach64_private_t *dev_priv, + drm_mach64_freelist_t *entry) +{ + int bytes, pages, remainder; + u32 address, page; + int i; + struct drm_buf *buf = entry->buf; + RING_LOCALS; + + bytes = buf->used - MACH64_HOSTDATA_BLIT_OFFSET; + pages = (bytes + MACH64_DMA_CHUNKSIZE - 1) / MACH64_DMA_CHUNKSIZE; + address = GETBUFADDR( buf ); + + BEGIN_RING( 4 + pages * 4 ); + + OUT_RING( MACH64_APERTURE_OFFSET + MACH64_BM_ADDR ); + OUT_RING( address ); + OUT_RING( MACH64_HOSTDATA_BLIT_OFFSET | MACH64_DMA_HOLD_OFFSET ); + OUT_RING( 0 ); + address += MACH64_HOSTDATA_BLIT_OFFSET; + + for ( i = 0 ; i < pages-1 ; i++ ) { + page = address + i * MACH64_DMA_CHUNKSIZE; + OUT_RING( MACH64_APERTURE_OFFSET + MACH64_BM_HOSTDATA ); + OUT_RING( page ); + OUT_RING( MACH64_DMA_CHUNKSIZE | MACH64_DMA_HOLD_OFFSET ); + OUT_RING( 0 ); + } + + /* generate the final descriptor for any remaining commands in this buffer */ + page = address + i * MACH64_DMA_CHUNKSIZE; + remainder = bytes - i * MACH64_DMA_CHUNKSIZE; + + /* Save dword offset of last descriptor for this buffer. + * This is needed to check for completion of the buffer in freelist_get + */ + entry->ring_ofs = RING_WRITE_OFS; + + OUT_RING( MACH64_APERTURE_OFFSET + MACH64_BM_HOSTDATA ); + OUT_RING( page ); + OUT_RING( remainder | MACH64_DMA_HOLD_OFFSET | MACH64_DMA_EOL ); + OUT_RING( 0 ); + + ADVANCE_RING(); + + return 0; +} + +/*@}*/ + + /*******************************************************************/ /** \name DMA test and initialization */ /*@{*/ -- cgit v1.2.3 From 7d08b816b7af3cd415bebf65f44313415fea091a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Fonseca?= Date: Sat, 8 Dec 2007 19:21:27 +0000 Subject: mach64: comment bus master / ring buffer behavior and security --- shared-core/mach64_dma.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'shared-core/mach64_dma.c') diff --git a/shared-core/mach64_dma.c b/shared-core/mach64_dma.c index 9aa3f768..411b98d5 100644 --- a/shared-core/mach64_dma.c +++ b/shared-core/mach64_dma.c @@ -562,6 +562,14 @@ void mach64_dump_ring_info(drm_mach64_private_t * dev_priv) /** \name DMA descriptor ring macros */ /*@{*/ +/** + * Add the end mark to the ring's new tail position. + * + * The bus master engine will keep processing the DMA buffers listed in the ring + * until it finds this mark, making it stop. + * + * \sa mach64_clear_dma_eol + */ static __inline__ void mach64_set_dma_eol(volatile u32 * addr) { #if defined(__i386__) @@ -602,6 +610,17 @@ static __inline__ void mach64_set_dma_eol(volatile u32 * addr) #endif } +/** + * Remove the end mark from the ring's old tail position. + * + * It should be called after calling mach64_set_dma_eol to mark the ring's new + * tail position. + * + * We update the end marks while the bus master engine is in operation. Since + * the bus master engine may potentially be reading from the same position + * that we write, we must change atomically to avoid having intermediary bad + * data. + */ static __inline__ void mach64_clear_dma_eol(volatile u32 * addr) { #if defined(__i386__) @@ -691,7 +710,9 @@ do { \ mach64_ring_tick( dev_priv, &(dev_priv)->ring ); \ } while (0) - +/** + * Queue a DMA buffer of registers writes into the ring buffer. + */ int mach64_add_buf_to_ring(drm_mach64_private_t *dev_priv, drm_mach64_freelist_t *entry) { @@ -734,6 +755,11 @@ int mach64_add_buf_to_ring(drm_mach64_private_t *dev_priv, return 0; } +/** + * Queue DMA buffer controlling host data tranfers (e.g., blit). + * + * Almost identical to mach64_add_buf_to_ring. + */ int mach64_add_hostdata_buf_to_ring(drm_mach64_private_t *dev_priv, drm_mach64_freelist_t *entry) { -- cgit v1.2.3