xref: /utopia/UTPA2-700.0.x/modules/usb/drv/usb_ecos/newhost/drvPCIMEM.c (revision 53ee8cc121a030b8d368113ac3e966b4705770ef)
1 //<MStar Software>
2 //******************************************************************************
3 // MStar Software
4 // Copyright (c) 2010 - 2012 MStar Semiconductor, Inc. All rights reserved.
5 // All software, firmware and related documentation herein ("MStar Software") are
6 // intellectual property of MStar Semiconductor, Inc. ("MStar") and protected by
7 // law, including, but not limited to, copyright law and international treaties.
8 // Any use, modification, reproduction, retransmission, or republication of all
9 // or part of MStar Software is expressly prohibited, unless prior written
10 // permission has been granted by MStar.
11 //
12 // By accessing, browsing and/or using MStar Software, you acknowledge that you
13 // have read, understood, and agree, to be bound by below terms ("Terms") and to
14 // comply with all applicable laws and regulations:
15 //
16 // 1. MStar shall retain any and all right, ownership and interest to MStar
17 //    Software and any modification/derivatives thereof.
18 //    No right, ownership, or interest to MStar Software and any
19 //    modification/derivatives thereof is transferred to you under Terms.
20 //
21 // 2. You understand that MStar Software might include, incorporate or be
22 //    supplied together with third party`s software and the use of MStar
23 //    Software may require additional licenses from third parties.
24 //    Therefore, you hereby agree it is your sole responsibility to separately
25 //    obtain any and all third party right and license necessary for your use of
26 //    such third party`s software.
27 //
28 // 3. MStar Software and any modification/derivatives thereof shall be deemed as
29 //    MStar`s confidential information and you agree to keep MStar`s
30 //    confidential information in strictest confidence and not disclose to any
31 //    third party.
32 //
33 // 4. MStar Software is provided on an "AS IS" basis without warranties of any
34 //    kind. Any warranties are hereby expressly disclaimed by MStar, including
35 //    without limitation, any warranties of merchantability, non-infringement of
36 //    intellectual property rights, fitness for a particular purpose, error free
37 //    and in conformity with any international standard.  You agree to waive any
38 //    claim against MStar for any loss, damage, cost or expense that you may
39 //    incur related to your use of MStar Software.
40 //    In no event shall MStar be liable for any direct, indirect, incidental or
41 //    consequential damages, including without limitation, lost of profit or
42 //    revenues, lost or damage of data, and unauthorized system use.
43 //    You agree that this Section 4 shall still apply without being affected
44 //    even if MStar Software has been modified by MStar in accordance with your
45 //    request or instruction for your use, except otherwise agreed by both
46 //    parties in writing.
47 //
48 // 5. If requested, MStar may from time to time provide technical supports or
49 //    services in relation with MStar Software to you for your use of
50 //    MStar Software in conjunction with your or your customer`s product
51 //    ("Services").
52 //    You understand and agree that, except otherwise agreed by both parties in
53 //    writing, Services are provided on an "AS IS" basis and the warranty
54 //    disclaimer set forth in Section 4 above shall apply.
55 //
56 // 6. Nothing contained herein shall be construed as by implication, estoppels
57 //    or otherwise:
58 //    (a) conferring any license or right to use MStar name, trademark, service
59 //        mark, symbol or any other identification;
60 //    (b) obligating MStar or any of its affiliates to furnish any person,
61 //        including without limitation, you and your customers, any assistance
62 //        of any kind whatsoever, or any information; or
63 //    (c) conferring any license or right under any intellectual property right.
64 //
65 // 7. These terms shall be governed by and construed in accordance with the laws
66 //    of Taiwan, R.O.C., excluding its conflict of law rules.
67 //    Any and all dispute arising out hereof or related hereto shall be finally
68 //    settled by arbitration referred to the Chinese Arbitration Association,
69 //    Taipei in accordance with the ROC Arbitration Law and the Arbitration
70 //    Rules of the Association by three (3) arbitrators appointed in accordance
71 //    with the said Rules.
72 //    The place of arbitration shall be in Taipei, Taiwan and the language shall
73 //    be English.
74 //    The arbitration award shall be final and binding to both parties.
75 //
76 //******************************************************************************
77 //<MStar Software>
78 
79 //#include <MsCommon.h> // NUSED
80 //#include "include/drvPCIMEM.h" // NUSED
81 #include "include/drvKernel.h"
82 #include "include/drvBitops.h"
83 #include "drvUsbHostConfig.h"
84 
85 /**
86      * @brief               Return a memory pool to be used to allocate memory by the requested characteristics.
87      *
88      * @param pName          name of memory pool
89      *
90      * @param u32Size         block size in the pool.
91      *
92      * @param u32AlignLen   block alignment size.
93      *
94      * @param U32CrossLimit  returned blocks can't cross the boundray.
95      *
96      * @return  ms_mem_pool     return memory pool with the requested characteristics.
97      */
ms_mem_pool_create(const char * pName,MS_U32 u32Size,MS_U32 u32AlignLen,MS_U32 U32CrossLimit)98 struct ms_mem_pool *ms_mem_pool_create (const char *pName, MS_U32 u32Size, MS_U32 u32AlignLen, MS_U32 U32CrossLimit)
99 {
100     struct ms_mem_pool    *pPool;
101 
102     if (u32AlignLen == 0)
103         u32AlignLen = 1;
104     if (u32Size == 0)
105         return 0;
106     else if (u32Size < u32AlignLen)
107     u32Size = u32AlignLen;
108     else if ((u32Size % u32AlignLen) != 0)
109     {
110         u32Size += u32AlignLen + 1;
111         u32Size &= ~(u32AlignLen - 1);
112     }
113 
114     if (U32CrossLimit == 0)
115     {
116         if (PAGE_SIZE < u32Size)
117             U32CrossLimit = u32Size;
118         else
119             U32CrossLimit = PAGE_SIZE;
120     }
121     else if (U32CrossLimit < u32Size)
122         return 0;
123 
124     if (!(pPool = (struct ms_mem_pool*) kmalloc (sizeof (*pPool), SLAB_KERNEL)))
125         return pPool;
126 
127     strncpy (pPool->name, pName, sizeof (pPool->name)-1 );
128     pPool->name[sizeof(pPool->name)-1] = '\0';
129     ms_list_init (&pPool->page_list);
130     pPool->size = u32Size;
131     pPool->allocation = U32CrossLimit;
132     pPool->blocks_per_page = U32CrossLimit / u32Size;
133     ms_usbhost_debug("ms_mem_pool_create: size=%d,allocation=%d bytes, %d blocks per page",
134         pPool->size, pPool->allocation, pPool->blocks_per_page);
135     return pPool;
136 }
137 
138 static struct ms_mem_page *
pool_alloc_page(struct ms_mem_pool * pMem_pool,int iFlags)139 pool_alloc_page (struct ms_mem_pool *pMem_pool, int iFlags)
140 {
141     struct ms_mem_page  *pPage;
142     int    mapsize;
143 
144     mapsize = pMem_pool->blocks_per_page;
145     mapsize = (mapsize + BITS_PER_LONG - 1) / BITS_PER_LONG;
146     mapsize *= sizeof (U32);
147 
148     pPage = (struct ms_mem_page *) kmalloc (mapsize + sizeof(struct ms_mem_page), iFlags);
149     ms_list_init(&pPage->page_list);
150     if (!pPage)
151         return 0;
152 
153     pPage->vaddr = ncmem_alloc_page(&pPage->dma);
154 
155     if (pPage->vaddr)
156     {
157         memset (pPage->bitmap, ((U32)-1), mapsize);  // bit set == free
158         ms_insert_list_after (&pPage->page_list, &pMem_pool->page_list);
159     }
160     else
161     {
162         kfree (pPage);
163         pPage = 0;
164     }
165     return pPage;
166 }
167 
168 /**
169      * @brief                       Allocate a block of memory
170      *
171      * @param pMem_pool    The pool to allocate memory.
172      *
173      * @param iFlags            memory flag.
174      *
175      * @param pDma_addr     pointer to physical address of block
176      *
177      * @return                      pointer to virtual address of block
178      */
ms_mem_pool_alloc(struct ms_mem_pool * pMem_pool,int iFlags,dma_addr_t * pDma_addr)179 void *ms_mem_pool_alloc (struct ms_mem_pool *pMem_pool, int iFlags, dma_addr_t *pDma_addr)
180 {
181     U32    u32flag;
182     struct list_head  *entry;
183     struct ms_mem_page    *ms_page;
184     int      iMap, iBlock;
185     U32      u32Offset;
186     void     *ms_retval;
187 
188     osapi_spin_lock_irqsave (&pMem_pool->lock, u32flag);
189     list_for_loop (entry, &pMem_pool->page_list)
190     {
191         U32    i;
192 
193         const struct list_head *__mptr = entry;
194         ms_page = (struct ms_mem_page *)( (char *)__mptr - (char *)offsetof(struct ms_mem_page,page_list));
195 
196         /* only cachable accesses here ... */
197         for (iMap = 0, i = 0; i < pMem_pool->blocks_per_page; i += BITS_PER_LONG, iMap++)
198         {
199             if (ms_page->bitmap [iMap] == 0)
200                 continue;
201             iBlock = ms_find_1st_zero (~ ms_page->bitmap [iMap]);
202             if ((i + iBlock) < pMem_pool->blocks_per_page)
203             {
204                 ms_clear_bit ( iBlock, &ms_page->bitmap [iMap],U32);
205                 u32Offset = (BITS_PER_LONG * iMap) + iBlock;
206                 u32Offset *= pMem_pool->size;
207                 goto ready;
208             }
209         }
210     }
211 
212     if (!(ms_page = pool_alloc_page (pMem_pool, iFlags)))
213     {
214         diag_printf("pool allocate page fail\n");
215         ms_retval = 0;
216         goto done;
217     }
218 
219     ms_clear_bit (0, &ms_page->bitmap [0],U32);
220     u32Offset = 0;
221 ready:
222     ms_retval = (void*) (u32Offset + (size_t) ( ms_page->vaddr ));
223     *pDma_addr = u32Offset + ms_page->dma;
224 done:
225     osapi_spin_unlock_irqrestore (&pMem_pool->lock, u32flag);
226     //ms_usbhost_debug("The allocated addr is %p, block size is %d ,bit_map[%d] is 0x%08X",
227     //    ms_retval, pMem_pool->size ,iMap,(U32)ms_page->bitmap [iMap]);
228     return ms_retval;
229 }
230 
__is_page_busy(int ms_blocks,U32 * ms_bitmap)231 static __inline__ int __is_page_busy (int ms_blocks, U32 *ms_bitmap)
232 {
233     while (ms_blocks > 0)
234     {
235         if (*ms_bitmap++ != ~0UL)
236             return 1;
237         ms_blocks -= BITS_PER_LONG;
238     }
239     return 0;
240 }
241 
242 /**
243      * @brief                       Destory memory pool
244      *
245      * @param pMem_pool    The pool to be destoryed.
246      *
247      * @return                     None
248      */
ms_mem_pool_destroy(struct ms_mem_pool * pMem_pool)249 void ms_mem_pool_destroy (struct ms_mem_pool *pMem_pool)
250 {
251     U32    u32flag;
252 
253     osapi_spin_lock_irqsave (&pMem_pool->lock, u32flag);
254     while (!ms_is_empty_list (&pMem_pool->page_list))
255     {
256         struct ms_mem_page    *ms_page;
257 
258         const struct list_head *__mptr = pMem_pool->page_list.next;
259         ms_page = (struct ms_mem_page *)( (char *)__mptr - (char *)offsetof(struct ms_mem_page,page_list) );
260 
261         if (__is_page_busy (pMem_pool->blocks_per_page, ms_page->bitmap))
262         {
263             diag_printf ("ms_mem_pool_destroy %s, %p busy\n",
264                 pMem_pool->name, ms_page->vaddr);
265             /* leak the still-in-use consistent memory */
266             ms_list_remove (&ms_page->page_list);
267             kfree (ms_page);
268         }
269         else
270         {
271 			ncmem_free_page((U32)ms_page->vaddr);
272 			ms_list_remove (&ms_page->page_list);
273 			kfree (ms_page);
274         }
275 
276     }
277     osapi_spin_unlock_irqrestore (&pMem_pool->lock, u32flag);
278     kfree (pMem_pool);
279 }
280 
281 /**
282      * @brief               Free memory block and put back into pool
283      *
284      * @param pMem_pool    The pool contains the block.
285      *
286      * @param pVirt_addr     Virtual address of the blcok.
287      *
288      * @param dma_addr      Physical address of the block.
289      *
290      * @return  BOOL           success or not
291      */
ms_mem_pool_free(struct ms_mem_pool * pMem_pool,void * pVirt_addr,dma_addr_t dma_addr)292 MS_BOOL ms_mem_pool_free (struct ms_mem_pool *pMem_pool, void *pVirt_addr, dma_addr_t dma_addr)
293 {
294     struct ms_mem_page   *ms_page;
295     struct list_head  *pEntry;
296     U32      u32flag;
297     int      iMap, iBlock;
298 
299     // find page in memory pool
300 	osapi_spin_lock_irqsave (&pMem_pool->lock, u32flag);
301 	list_for_loop (pEntry, &pMem_pool->page_list)
302 	{
303 		//page = list_entry (entry, struct ms_mem_page, page_list);
304 		const struct list_head *__mptr = pEntry;
305 		ms_page = (struct ms_mem_page *)( (char *)__mptr - (char *)offsetof(struct ms_mem_page,page_list) );
306 
307 		if (dma_addr < ms_page->dma)
308 			continue;
309 		if (dma_addr < (ms_page->dma + pMem_pool->allocation))
310 			goto page_found;
311 	}
312 
313 	//Not found !!
314 	osapi_spin_unlock_irqrestore (&pMem_pool->lock, u32flag);
315     ms_usbhost_debug ("ms_mem_pool_free %s, %p/%lx (bad dma)\n", pMem_pool->name, pVirt_addr, (U32) dma_addr);
316     return FALSE;
317 
318 
319 page_found:
320 	osapi_spin_unlock_irqrestore (&pMem_pool->lock, u32flag);
321 
322     iBlock = dma_addr - ms_page->dma;
323     iBlock /= pMem_pool->size;
324     iMap = iBlock / BITS_PER_LONG;
325     iBlock %= BITS_PER_LONG;
326 
327     osapi_spin_lock_irqsave (&pMem_pool->lock, u32flag);
328     ms_set_bit (iBlock, &ms_page->bitmap [iMap], U32);
329     ms_usbhost_debug("Free Block: addr=0x%08X bitmap is 0x%08X",dma_addr,(U32)ms_page->bitmap [iMap]);
330 
331     ////   if (!is_page_busy(bpp, page->bitmap)) pool_free_page(pool, page);
332     ////   it is not interrupt safe. Better have empty pages hang around.
333 
334     osapi_spin_unlock_irqrestore (&pMem_pool->lock, u32flag);
335     return TRUE;
336 }
337 
338