sym_malloc.c 8.7 KB

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