sym_malloc.c 8.0 KB

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