/* Allocates resources for an SGE descriptor ring, such as Tx queues, free buffer lists, or response queues. Each SGE ring requires space for its HW descriptors plus, optionally, space for the SW state associated with each HW entry (the metadata). The function returns three values: the virtual address for the HW ring (the return value of the function), the physical address of the HW ring, and the address of the SW ring.  */
static void* alloc_ring(struct pci_dev *pdev, size_t nelem, size_t elem_size, size_t sw_size, dma_addr_t *phys, void *metadata)
/* Allocates resources for an SGE descriptor ring, such as Tx queues, free buffer lists, or response queues. Each SGE ring requires space for its HW descriptors plus, optionally, space for the SW state associated with each HW entry (the metadata). The function returns three values: the virtual address for the HW ring (the return value of the function), the physical address of the HW ring, and the address of the SW ring.  */
static void* alloc_ring(struct pci_dev *pdev, size_t nelem, size_t elem_size, size_t sw_size, dma_addr_t *phys, void *metadata)
{
	size_t len = nelem * elem_size;
	void *s = NULL;
	void *p = dma_alloc_coherent(&pdev->dev, len, phys, GFP_KERNEL);
	if (!p)
		return NULL;
	if (sw_size && metadata) {
		s = kcalloc(nelem, sw_size, GFP_KERNEL);
		if (!s) {
			dma_free_coherent(&pdev->dev, len, p, *phys);
			return NULL;
		}
		*(void **)metadata = s;
	}
	memset(p, 0, len);
	return p;
}