brintos

brintos / linux-shallow public Read only

0
0
Text · 8.0 KiB · eb5c045 Raw
366 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 4 * of PCI-SCSI IO processors.5 *6 * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>7 *8 * This driver is derived from the Linux sym53c8xx driver.9 * Copyright (C) 1998-2000  Gerard Roudier10 *11 * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 12 * a port of the FreeBSD ncr driver to Linux-1.2.13.13 *14 * The original ncr driver has been written for 386bsd and FreeBSD by15 *         Wolfgang Stanglmeier        <wolf@cologne.de>16 *         Stefan Esser                <se@mi.Uni-Koeln.de>17 * Copyright (C) 1994  Wolfgang Stanglmeier18 *19 * Other major contributions:20 *21 * NVRAM detection and reading.22 * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>23 *24 *-----------------------------------------------------------------------------25 */26 27#include "sym_glue.h"28 29/*30 *  Simple power of two buddy-like generic allocator.31 *  Provides naturally aligned memory chunks.32 *33 *  This simple code is not intended to be fast, but to 34 *  provide power of 2 aligned memory allocations.35 *  Since the SCRIPTS processor only supplies 8 bit arithmetic, 36 *  this allocator allows simple and fast address calculations  37 *  from the SCRIPTS code. In addition, cache line alignment 38 *  is guaranteed for power of 2 cache line size.39 *40 *  This allocator has been developed for the Linux sym53c8xx  41 *  driver, since this O/S does not provide naturally aligned 42 *  allocations.43 *  It has the advantage of allowing the driver to use private 44 *  pages of memory that will be useful if we ever need to deal 45 *  with IO MMUs for PCI.46 */47static void *___sym_malloc(m_pool_p mp, int size)48{49	int i = 0;50	int s = (1 << SYM_MEM_SHIFT);51	int j;52	void *a;53	m_link_p h = mp->h;54 55	if (size > SYM_MEM_CLUSTER_SIZE)56		return NULL;57 58	while (size > s) {59		s <<= 1;60		++i;61	}62 63	j = i;64	while (!h[j].next) {65		if (s == SYM_MEM_CLUSTER_SIZE) {66			h[j].next = (m_link_p) M_GET_MEM_CLUSTER();67			if (h[j].next)68				h[j].next->next = NULL;69			break;70		}71		++j;72		s <<= 1;73	}74	a = h[j].next;75	if (a) {76		h[j].next = h[j].next->next;77		while (j > i) {78			j -= 1;79			s >>= 1;80			h[j].next = (m_link_p) (a+s);81			h[j].next->next = NULL;82		}83	}84#ifdef DEBUG85	printf("___sym_malloc(%d) = %p\n", size, (void *) a);86#endif87	return a;88}89 90/*91 *  Counter-part of the generic allocator.92 */93static void ___sym_mfree(m_pool_p mp, void *ptr, int size)94{95	int i = 0;96	int s = (1 << SYM_MEM_SHIFT);97	m_link_p q;98	unsigned long a, b;99	m_link_p h = mp->h;100 101#ifdef DEBUG102	printf("___sym_mfree(%p, %d)\n", ptr, size);103#endif104 105	if (size > SYM_MEM_CLUSTER_SIZE)106		return;107 108	while (size > s) {109		s <<= 1;110		++i;111	}112 113	a = (unsigned long)ptr;114 115	while (1) {116		if (s == SYM_MEM_CLUSTER_SIZE) {117#ifdef SYM_MEM_FREE_UNUSED118			M_FREE_MEM_CLUSTER((void *)a);119#else120			((m_link_p) a)->next = h[i].next;121			h[i].next = (m_link_p) a;122#endif123			break;124		}125		b = a ^ s;126		q = &h[i];127		while (q->next && q->next != (m_link_p) b) {128			q = q->next;129		}130		if (!q->next) {131			((m_link_p) a)->next = h[i].next;132			h[i].next = (m_link_p) a;133			break;134		}135		q->next = q->next->next;136		a = a & b;137		s <<= 1;138		++i;139	}140}141 142/*143 *  Verbose and zeroing allocator that wrapps to the generic allocator.144 */145static void *__sym_calloc2(m_pool_p mp, int size, char *name, int uflags)146{147	void *p;148 149	p = ___sym_malloc(mp, size);150 151	if (DEBUG_FLAGS & DEBUG_ALLOC) {152		printf ("new %-10s[%4d] @%p.\n", name, size, p);153	}154 155	if (p)156		memset(p, 0, size);157	else if (uflags & SYM_MEM_WARN)158		printf ("__sym_calloc2: failed to allocate %s[%d]\n", name, size);159	return p;160}161#define __sym_calloc(mp, s, n)	__sym_calloc2(mp, s, n, SYM_MEM_WARN)162 163/*164 *  Its counter-part.165 */166static void __sym_mfree(m_pool_p mp, void *ptr, int size, char *name)167{168	if (DEBUG_FLAGS & DEBUG_ALLOC)169		printf ("freeing %-10s[%4d] @%p.\n", name, size, ptr);170 171	___sym_mfree(mp, ptr, size);172}173 174/*175 *  Default memory pool we donnot need to involve in DMA.176 *177 *  With DMA abstraction, we use functions (methods), to 178 *  distinguish between non DMAable memory and DMAable memory.179 */180static void *___mp0_get_mem_cluster(m_pool_p mp)181{182	void *m = sym_get_mem_cluster();183	if (m)184		++mp->nump;185	return m;186}187 188#ifdef	SYM_MEM_FREE_UNUSED189static void ___mp0_free_mem_cluster(m_pool_p mp, void *m)190{191	sym_free_mem_cluster(m);192	--mp->nump;193}194#else195#define ___mp0_free_mem_cluster NULL196#endif197 198static struct sym_m_pool mp0 = {199	NULL,200	___mp0_get_mem_cluster,201	___mp0_free_mem_cluster202};203 204/*205 *  Methods that maintains DMAable pools according to user allocations.206 *  New pools are created on the fly when a new pool id is provided.207 *  They are deleted on the fly when they get emptied.208 */209/* Get a memory cluster that matches the DMA constraints of a given pool */210static void * ___get_dma_mem_cluster(m_pool_p mp)211{212	m_vtob_p vbp;213	void *vaddr;214 215	vbp = __sym_calloc(&mp0, sizeof(*vbp), "VTOB");216	if (!vbp)217		goto out_err;218 219	vaddr = sym_m_get_dma_mem_cluster(mp, vbp);220	if (vaddr) {221		int hc = VTOB_HASH_CODE(vaddr);222		vbp->next = mp->vtob[hc];223		mp->vtob[hc] = vbp;224		++mp->nump;225	}226	return vaddr;227out_err:228	return NULL;229}230 231#ifdef	SYM_MEM_FREE_UNUSED232/* Free a memory cluster and associated resources for DMA */233static void ___free_dma_mem_cluster(m_pool_p mp, void *m)234{235	m_vtob_p *vbpp, vbp;236	int hc = VTOB_HASH_CODE(m);237 238	vbpp = &mp->vtob[hc];239	while (*vbpp && (*vbpp)->vaddr != m)240		vbpp = &(*vbpp)->next;241	if (*vbpp) {242		vbp = *vbpp;243		*vbpp = (*vbpp)->next;244		sym_m_free_dma_mem_cluster(mp, vbp);245		__sym_mfree(&mp0, vbp, sizeof(*vbp), "VTOB");246		--mp->nump;247	}248}249#endif250 251/* Fetch the memory pool for a given pool id (i.e. DMA constraints) */252static inline m_pool_p ___get_dma_pool(m_pool_ident_t dev_dmat)253{254	m_pool_p mp;255	for (mp = mp0.next;256		mp && !sym_m_pool_match(mp->dev_dmat, dev_dmat);257			mp = mp->next);258	return mp;259}260 261/* Create a new memory DMAable pool (when fetch failed) */262static m_pool_p ___cre_dma_pool(m_pool_ident_t dev_dmat)263{264	m_pool_p mp = __sym_calloc(&mp0, sizeof(*mp), "MPOOL");265	if (mp) {266		mp->dev_dmat = dev_dmat;267		mp->get_mem_cluster = ___get_dma_mem_cluster;268#ifdef	SYM_MEM_FREE_UNUSED269		mp->free_mem_cluster = ___free_dma_mem_cluster;270#endif271		mp->next = mp0.next;272		mp0.next = mp;273		return mp;274	}275	return NULL;276}277 278#ifdef	SYM_MEM_FREE_UNUSED279/* Destroy a DMAable memory pool (when got emptied) */280static void ___del_dma_pool(m_pool_p p)281{282	m_pool_p *pp = &mp0.next;283 284	while (*pp && *pp != p)285		pp = &(*pp)->next;286	if (*pp) {287		*pp = (*pp)->next;288		__sym_mfree(&mp0, p, sizeof(*p), "MPOOL");289	}290}291#endif292 293/* This lock protects only the memory allocation/free.  */294static DEFINE_SPINLOCK(sym53c8xx_lock);295 296/*297 *  Actual allocator for DMAable memory.298 */299void *__sym_calloc_dma(m_pool_ident_t dev_dmat, int size, char *name)300{301	unsigned long flags;302	m_pool_p mp;303	void *m = NULL;304 305	spin_lock_irqsave(&sym53c8xx_lock, flags);306	mp = ___get_dma_pool(dev_dmat);307	if (!mp)308		mp = ___cre_dma_pool(dev_dmat);309	if (!mp)310		goto out;311	m = __sym_calloc(mp, size, name);312#ifdef	SYM_MEM_FREE_UNUSED313	if (!mp->nump)314		___del_dma_pool(mp);315#endif316 317 out:318	spin_unlock_irqrestore(&sym53c8xx_lock, flags);319	return m;320}321 322void __sym_mfree_dma(m_pool_ident_t dev_dmat, void *m, int size, char *name)323{324	unsigned long flags;325	m_pool_p mp;326 327	spin_lock_irqsave(&sym53c8xx_lock, flags);328	mp = ___get_dma_pool(dev_dmat);329	if (!mp)330		goto out;331	__sym_mfree(mp, m, size, name);332#ifdef	SYM_MEM_FREE_UNUSED333	if (!mp->nump)334		___del_dma_pool(mp);335#endif336 out:337	spin_unlock_irqrestore(&sym53c8xx_lock, flags);338}339 340/*341 *  Actual virtual to bus physical address translator 342 *  for 32 bit addressable DMAable memory.343 */344dma_addr_t __vtobus(m_pool_ident_t dev_dmat, void *m)345{346	unsigned long flags;347	m_pool_p mp;348	int hc = VTOB_HASH_CODE(m);349	m_vtob_p vp = NULL;350	void *a = (void *)((unsigned long)m & ~SYM_MEM_CLUSTER_MASK);351	dma_addr_t b;352 353	spin_lock_irqsave(&sym53c8xx_lock, flags);354	mp = ___get_dma_pool(dev_dmat);355	if (mp) {356		vp = mp->vtob[hc];357		while (vp && vp->vaddr != a)358			vp = vp->next;359	}360	if (!vp)361		panic("sym: VTOBUS FAILED!\n");362	b = vp->baddr + (m - a);363	spin_unlock_irqrestore(&sym53c8xx_lock, flags);364	return b;365}366