sym_malloc.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  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. #include "sym_glue.h"
  40. /*
  41. * Simple power of two buddy-like generic allocator.
  42. * Provides naturally aligned memory chunks.
  43. *
  44. * This simple code is not intended to be fast, but to
  45. * provide power of 2 aligned memory allocations.
  46. * Since the SCRIPTS processor only supplies 8 bit arithmetic,
  47. * this allocator allows simple and fast address calculations
  48. * from the SCRIPTS code. In addition, cache line alignment
  49. * is guaranteed for power of 2 cache line size.
  50. *
  51. * This allocator has been developed for the Linux sym53c8xx
  52. * driver, since this O/S does not provide naturally aligned
  53. * allocations.
  54. * It has the advantage of allowing the driver to use private
  55. * pages of memory that will be useful if we ever need to deal
  56. * with IO MMUs for PCI.
  57. */
  58. static void *___sym_malloc(m_pool_p mp, int size)
  59. {
  60. int i = 0;
  61. int s = (1 << SYM_MEM_SHIFT);
  62. int j;
  63. void *a;
  64. m_link_p h = mp->h;
  65. if (size > SYM_MEM_CLUSTER_SIZE)
  66. return NULL;
  67. while (size > s) {
  68. s <<= 1;
  69. ++i;
  70. }
  71. j = i;
  72. while (!h[j].next) {
  73. if (s == SYM_MEM_CLUSTER_SIZE) {
  74. h[j].next = (m_link_p) M_GET_MEM_CLUSTER();
  75. if (h[j].next)
  76. h[j].next->next = NULL;
  77. break;
  78. }
  79. ++j;
  80. s <<= 1;
  81. }
  82. a = h[j].next;
  83. if (a) {
  84. h[j].next = h[j].next->next;
  85. while (j > i) {
  86. j -= 1;
  87. s >>= 1;
  88. h[j].next = (m_link_p) (a+s);
  89. h[j].next->next = NULL;
  90. }
  91. }
  92. #ifdef DEBUG
  93. printf("___sym_malloc(%d) = %p\n", size, (void *) a);
  94. #endif
  95. return a;
  96. }
  97. /*
  98. * Counter-part of the generic allocator.
  99. */
  100. static void ___sym_mfree(m_pool_p mp, void *ptr, int size)
  101. {
  102. int i = 0;
  103. int s = (1 << SYM_MEM_SHIFT);
  104. m_link_p q;
  105. unsigned long a, b;
  106. m_link_p h = mp->h;
  107. #ifdef DEBUG
  108. printf("___sym_mfree(%p, %d)\n", ptr, size);
  109. #endif
  110. if (size > SYM_MEM_CLUSTER_SIZE)
  111. return;
  112. while (size > s) {
  113. s <<= 1;
  114. ++i;
  115. }
  116. a = (unsigned long)ptr;
  117. while (1) {
  118. if (s == SYM_MEM_CLUSTER_SIZE) {
  119. #ifdef SYM_MEM_FREE_UNUSED
  120. M_FREE_MEM_CLUSTER((void *)a);
  121. #else
  122. ((m_link_p) a)->next = h[i].next;
  123. h[i].next = (m_link_p) a;
  124. #endif
  125. break;
  126. }
  127. b = a ^ s;
  128. q = &h[i];
  129. while (q->next && q->next != (m_link_p) b) {
  130. q = q->next;
  131. }
  132. if (!q->next) {
  133. ((m_link_p) a)->next = h[i].next;
  134. h[i].next = (m_link_p) a;
  135. break;
  136. }
  137. q->next = q->next->next;
  138. a = a & b;
  139. s <<= 1;
  140. ++i;
  141. }
  142. }
  143. /*
  144. * Verbose and zeroing allocator that wrapps to the generic allocator.
  145. */
  146. static void *__sym_calloc2(m_pool_p mp, int size, char *name, int uflags)
  147. {
  148. void *p;
  149. p = ___sym_malloc(mp, size);
  150. if (DEBUG_FLAGS & DEBUG_ALLOC) {
  151. printf ("new %-10s[%4d] @%p.\n", name, size, p);
  152. }
  153. if (p)
  154. memset(p, 0, size);
  155. else if (uflags & SYM_MEM_WARN)
  156. printf ("__sym_calloc2: failed to allocate %s[%d]\n", name, size);
  157. return p;
  158. }
  159. #define __sym_calloc(mp, s, n) __sym_calloc2(mp, s, n, SYM_MEM_WARN)
  160. /*
  161. * Its counter-part.
  162. */
  163. static void __sym_mfree(m_pool_p mp, void *ptr, int size, char *name)
  164. {
  165. if (DEBUG_FLAGS & DEBUG_ALLOC)
  166. printf ("freeing %-10s[%4d] @%p.\n", name, size, ptr);
  167. ___sym_mfree(mp, ptr, size);
  168. }
  169. /*
  170. * Default memory pool we donnot need to involve in DMA.
  171. *
  172. * With DMA abstraction, we use functions (methods), to
  173. * distinguish between non DMAable memory and DMAable memory.
  174. */
  175. static void *___mp0_get_mem_cluster(m_pool_p mp)
  176. {
  177. void *m = sym_get_mem_cluster();
  178. if (m)
  179. ++mp->nump;
  180. return m;
  181. }
  182. #ifdef SYM_MEM_FREE_UNUSED
  183. static void ___mp0_free_mem_cluster(m_pool_p mp, void *m)
  184. {
  185. sym_free_mem_cluster(m);
  186. --mp->nump;
  187. }
  188. #else
  189. #define ___mp0_free_mem_cluster NULL
  190. #endif
  191. static struct sym_m_pool mp0 = {
  192. NULL,
  193. ___mp0_get_mem_cluster,
  194. ___mp0_free_mem_cluster
  195. };
  196. /*
  197. * Methods that maintains DMAable pools according to user allocations.
  198. * New pools are created on the fly when a new pool id is provided.
  199. * They are deleted on the fly when they get emptied.
  200. */
  201. /* Get a memory cluster that matches the DMA constraints of a given pool */
  202. static void * ___get_dma_mem_cluster(m_pool_p mp)
  203. {
  204. m_vtob_p vbp;
  205. void *vaddr;
  206. vbp = __sym_calloc(&mp0, sizeof(*vbp), "VTOB");
  207. if (!vbp)
  208. goto out_err;
  209. vaddr = sym_m_get_dma_mem_cluster(mp, vbp);
  210. if (vaddr) {
  211. int hc = VTOB_HASH_CODE(vaddr);
  212. vbp->next = mp->vtob[hc];
  213. mp->vtob[hc] = vbp;
  214. ++mp->nump;
  215. }
  216. return vaddr;
  217. out_err:
  218. return NULL;
  219. }
  220. #ifdef SYM_MEM_FREE_UNUSED
  221. /* Free a memory cluster and associated resources for DMA */
  222. static void ___free_dma_mem_cluster(m_pool_p mp, void *m)
  223. {
  224. m_vtob_p *vbpp, vbp;
  225. int hc = VTOB_HASH_CODE(m);
  226. vbpp = &mp->vtob[hc];
  227. while (*vbpp && (*vbpp)->vaddr != m)
  228. vbpp = &(*vbpp)->next;
  229. if (*vbpp) {
  230. vbp = *vbpp;
  231. *vbpp = (*vbpp)->next;
  232. sym_m_free_dma_mem_cluster(mp, vbp);
  233. __sym_mfree(&mp0, vbp, sizeof(*vbp), "VTOB");
  234. --mp->nump;
  235. }
  236. }
  237. #endif
  238. /* Fetch the memory pool for a given pool id (i.e. DMA constraints) */
  239. static inline m_pool_p ___get_dma_pool(m_pool_ident_t dev_dmat)
  240. {
  241. m_pool_p mp;
  242. for (mp = mp0.next;
  243. mp && !sym_m_pool_match(mp->dev_dmat, dev_dmat);
  244. mp = mp->next);
  245. return mp;
  246. }
  247. /* Create a new memory DMAable pool (when fetch failed) */
  248. static m_pool_p ___cre_dma_pool(m_pool_ident_t dev_dmat)
  249. {
  250. m_pool_p mp = __sym_calloc(&mp0, sizeof(*mp), "MPOOL");
  251. if (mp) {
  252. mp->dev_dmat = dev_dmat;
  253. mp->get_mem_cluster = ___get_dma_mem_cluster;
  254. #ifdef SYM_MEM_FREE_UNUSED
  255. mp->free_mem_cluster = ___free_dma_mem_cluster;
  256. #endif
  257. mp->next = mp0.next;
  258. mp0.next = mp;
  259. return mp;
  260. }
  261. return NULL;
  262. }
  263. #ifdef SYM_MEM_FREE_UNUSED
  264. /* Destroy a DMAable memory pool (when got emptied) */
  265. static void ___del_dma_pool(m_pool_p p)
  266. {
  267. m_pool_p *pp = &mp0.next;
  268. while (*pp && *pp != p)
  269. pp = &(*pp)->next;
  270. if (*pp) {
  271. *pp = (*pp)->next;
  272. __sym_mfree(&mp0, p, sizeof(*p), "MPOOL");
  273. }
  274. }
  275. #endif
  276. /* This lock protects only the memory allocation/free. */
  277. static DEFINE_SPINLOCK(sym53c8xx_lock);
  278. /*
  279. * Actual allocator for DMAable memory.
  280. */
  281. void *__sym_calloc_dma(m_pool_ident_t dev_dmat, int size, char *name)
  282. {
  283. unsigned long flags;
  284. m_pool_p mp;
  285. void *m = NULL;
  286. spin_lock_irqsave(&sym53c8xx_lock, flags);
  287. mp = ___get_dma_pool(dev_dmat);
  288. if (!mp)
  289. mp = ___cre_dma_pool(dev_dmat);
  290. if (!mp)
  291. goto out;
  292. m = __sym_calloc(mp, size, name);
  293. #ifdef SYM_MEM_FREE_UNUSED
  294. if (!mp->nump)
  295. ___del_dma_pool(mp);
  296. #endif
  297. out:
  298. spin_unlock_irqrestore(&sym53c8xx_lock, flags);
  299. return m;
  300. }
  301. void __sym_mfree_dma(m_pool_ident_t dev_dmat, void *m, int size, char *name)
  302. {
  303. unsigned long flags;
  304. m_pool_p mp;
  305. spin_lock_irqsave(&sym53c8xx_lock, flags);
  306. mp = ___get_dma_pool(dev_dmat);
  307. if (!mp)
  308. goto out;
  309. __sym_mfree(mp, m, size, name);
  310. #ifdef SYM_MEM_FREE_UNUSED
  311. if (!mp->nump)
  312. ___del_dma_pool(mp);
  313. #endif
  314. out:
  315. spin_unlock_irqrestore(&sym53c8xx_lock, flags);
  316. }
  317. /*
  318. * Actual virtual to bus physical address translator
  319. * for 32 bit addressable DMAable memory.
  320. */
  321. dma_addr_t __vtobus(m_pool_ident_t dev_dmat, void *m)
  322. {
  323. unsigned long flags;
  324. m_pool_p mp;
  325. int hc = VTOB_HASH_CODE(m);
  326. m_vtob_p vp = NULL;
  327. void *a = (void *)((unsigned long)m & ~SYM_MEM_CLUSTER_MASK);
  328. dma_addr_t b;
  329. spin_lock_irqsave(&sym53c8xx_lock, flags);
  330. mp = ___get_dma_pool(dev_dmat);
  331. if (mp) {
  332. vp = mp->vtob[hc];
  333. while (vp && vp->vaddr != a)
  334. vp = vp->next;
  335. }
  336. if (!vp)
  337. panic("sym: VTOBUS FAILED!\n");
  338. b = vp->baddr + (m - a);
  339. spin_unlock_irqrestore(&sym53c8xx_lock, flags);
  340. return b;
  341. }