Queues are used to hold either values or references that need to be passed between SW and HW components in the system. Queues are implemented in the PKTDMA and BCDMA modules using memory mapped rings. Each ring is comprised of a single contiguous memory block which contains an array of elements. Each element is 8 bytes. The size of the ring is selectable from 1 entry up to 64K entries with single entry granularity. Each ring is used to implement a forward and a reverse queue which share the same data elements but which have independent pointers and occupancies. The forward queue is used to pass work from SW to HW and the reverse queue is used to pass completed work back from HW to SW. A doorbell MMR is provided per ring to allow SW to add elements to the forward queue. A separate doorbell MMR is provided per ring to allow SW to acknowledge the popping of elements from the reverse queue. An occupancy MMR is provided for the reverse queue so that SW can know how many entries are currently completed. Entries are returned on the reverse queue in the exact same order and in the exact same index as the work was provided on the forward queue and because of this, the DMA controllers do not actually modify the ring entry for completion operations (the only exception being for acknowledgement of a teardown operation). Completion is indicated by incrementing of the reverse occupancy only.