⛏️ index : haiku.git

/*
 * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Copyright 2008, Axel DΓΆrfler, axeld@pinc-software.de.
 * Distributed under the terms of the MIT License.
 */
#ifndef DMA_RESOURCES_H
#define DMA_RESOURCES_H


#include <sys/uio.h>

#include <fs_interface.h>

#include <lock.h>
#include <util/DoublyLinkedList.h>
#include <util/iovec_support.h>


struct device_node;
struct IOOperation;
struct IORequest;


struct dma_restrictions {
	generic_addr_t	low_address;
	generic_addr_t	high_address;
	generic_size_t	alignment;
	generic_size_t	boundary;
	generic_size_t	max_transfer_size;
	uint32			max_segment_count;
	generic_size_t	max_segment_size;
	uint32			flags;
};


struct DMABounceBuffer : public DoublyLinkedListLinkImpl<DMABounceBuffer> {
	void*		address;
	phys_addr_t	physical_address;
	phys_size_t	size;
};

typedef DoublyLinkedList<DMABounceBuffer> DMABounceBufferList;


class DMABuffer : public DoublyLinkedListLinkImpl<DMABuffer> {
public:
	static	DMABuffer*			Create(size_t count);

			generic_io_vec*		Vecs() { return fVecs; }
			generic_io_vec&		VecAt(size_t index) { return fVecs[index]; }
			uint32				VecCount() const { return fVecCount; }
			void				SetVecCount(uint32 count);

			void				AddVec(generic_addr_t base,
									generic_size_t size);

			void				SetBounceBuffer(DMABounceBuffer* bounceBuffer)
									{ fBounceBuffer = bounceBuffer; }
			DMABounceBuffer*	BounceBuffer() const { return fBounceBuffer; }

			void*				BounceBufferAddress() const
									{ return fBounceBuffer
										? fBounceBuffer->address : NULL; }
			phys_addr_t			PhysicalBounceBufferAddress() const
									{ return fBounceBuffer
										? fBounceBuffer->physical_address
										: 0; }
			phys_size_t			BounceBufferSize() const
									{ return fBounceBuffer
										? fBounceBuffer->size : 0; }

			bool				UsesBounceBufferAt(uint32 index);

			void				Dump() const;

private:
			DMABounceBuffer*	fBounceBuffer;
			uint32				fVecCount;
			generic_io_vec		fVecs[1];
};


typedef DoublyLinkedList<DMABuffer> DMABufferList;


class DMAResource {
public:
								DMAResource();
								~DMAResource();

			status_t			Init(const dma_restrictions& restrictions,
									generic_size_t blockSize,
									uint32 bufferCount,
									uint32 bounceBufferCount);
			status_t			Init(device_node* node,
									generic_size_t blockSize,
									uint32 bufferCount,
									uint32 bounceBufferCount);

			status_t			CreateBuffer(DMABuffer** _buffer);
			status_t			CreateBounceBuffer(DMABounceBuffer** _buffer);

			status_t			TranslateNext(IORequest* request,
									IOOperation* operation,
									generic_size_t maxOperationLength);
			void				RecycleBuffer(DMABuffer* buffer);

			generic_size_t		BlockSize() const	{ return fBlockSize; }
			uint32				BufferCount() const { return fBufferCount; }

private:
			bool				_NeedsBoundsBuffers() const;
			void				_RestrictBoundaryAndSegmentSize(
									generic_addr_t base,
									generic_addr_t& length);
			void				_CutBuffer(DMABuffer& buffer,
									phys_addr_t& physicalBounceBuffer,
									phys_size_t& bounceLeft,
									generic_size_t toCut);
			phys_size_t			_AddBounceBuffer(DMABuffer& buffer,
									phys_addr_t& physicalBounceBuffer,
									phys_size_t& bounceLeft,
									generic_size_t length, bool fixedLength);

			mutex				fLock;
			dma_restrictions	fRestrictions;
			generic_size_t		fBlockSize;
			uint32				fBufferCount;
			uint32				fBounceBufferCount;
			phys_size_t			fBounceBufferSize;
			DMABufferList		fDMABuffers;
			DMABounceBufferList	fBounceBuffers;
			generic_io_vec*		fScratchVecs;
};

#endif	// DMA_RESOURCES_H