Subject: Re: m8260_cpm_dpalloc -> m8260_cpm_dpfree ?

From: Alex Zeffertt <[email-masked]>
Date: Fri, 25 Aug 2006 15:34:09 +0100

Keinen Namen wrote:
> Hi
> 
> Simple Question, I allocate Memory for my BDs with m8260_cpm_dpalloc, but there are no dpfree in Linux 2.4.25. In Linux 2.6 are a funktion to free dp memory.
> 
> Are there no funktion in Linux 2.4 ? 
> 

I've implemented the free function for my own benefit.  See attached patch
which should work against ELDK 3.1

Alex

Index: commproc.c
===================================================================
RCS file: /newcvs/pq2-linux/kernel/arch/ppc/8260_io/commproc.c,v
retrieving revision 1.1.1.1
retrieving revision 1.3
diff -u -r1.1.1.1 -r1.3
--- commproc.c	24 Aug 2005 12:05:13 -0000	1.1.1.1
+++ commproc.c	11 May 2006 13:14:31 -0000	1.3
@@ -29,12 +29,264 @@
 #include <asm/immap_8260.h>
 #include <asm/cpm_8260.h>
 
+#define DPFREE
+
+#ifdef DPFREE
+typedef struct	cpm_dpalloc_entry_s {
+	u_short				start_addr;
+    u_short             retloc;    /* This is start_addr + alignment offset: only valid in alloc list */
+	u_short				size;
+	struct	cpm_dpalloc_entry_s *	next_entr;
+} cpm_dpalloc_entry_t;
+
+static	void	cpm_dpalloc_init(void);
+static	void	cpm_dpalloc_data_init(cpm_dpalloc_entry_t  *);
+static	int	    cpm_dpalloc_cl(cpm_dpalloc_entry_t *);
+static	int  	cpm_dpalloc_rem(cpm_dpalloc_entry_t **, cpm_dpalloc_entry_t *);
+static	void	cpm_dpalloc_ins(cpm_dpalloc_entry_t **, cpm_dpalloc_entry_t *);
+# define CPM_DPALLOC_COUNT (CPM_DATAONLY_SIZE / sizeof(cbd_t) + 1)  
+/* Dynamic lists of allocated and free DPRAM */
+static	cpm_dpalloc_entry_t  *cpm_dpalloc_free;
+static	cpm_dpalloc_entry_t  *cpm_dpalloc_alloc;
+static	cpm_dpalloc_entry_t	cpm_dpalloc_list[CPM_DPALLOC_COUNT];
+#else
 static	uint	dp_alloc_base;	/* Starting offset in DP ram */
 static	uint	dp_alloc_top;	/* Max offset + 1 */
+#endif
 static	uint	host_buffer;	/* One page of host buffer */
 static	uint	host_end;	/* end + 1 */
 cpm8260_t	*cpmp;		/* Pointer to comm processor space */
 
+#ifdef DPFREE
+/* Initialize dynamic lists
+ */
+static void cpm_dpalloc_init(void)
+{
+	int i;
+
+	cpm_dpalloc_free = cpm_dpalloc_list;
+	cpm_dpalloc_free->start_addr = CPM_DATAONLY_BASE;
+	cpm_dpalloc_free->size = CPM_DATAONLY_SIZE;
+	cpm_dpalloc_free->next_entr = NULL;
+	cpm_dpalloc_alloc = NULL;
+
+	for(i = 1; i <= CPM_DPALLOC_COUNT; i++) {
+		cpm_dpalloc_data_init (cpm_dpalloc_list + i);
+	}
+}
+
+/* Initialize element in list of DPRAM
+ */
+static void cpm_dpalloc_data_init(cpm_dpalloc_entry_t * ptr)
+{
+	ptr->retloc = ptr->start_addr = 0;
+	ptr->size = 0;
+	ptr->next_entr = NULL;
+}
+
+static int cpm_dpalloc_cl(cpm_dpalloc_entry_t * head)
+{
+	cpm_dpalloc_entry_t	* curr;
+	cpm_dpalloc_entry_t	* next;
+	int			  retloc;
+
+	curr = head;
+	retloc = -1;
+
+	if (curr) {
+		retloc = 0;
+
+		while ((next = curr->next_entr)) {
+			if (curr->start_addr + curr->size == next->start_addr) {
+				curr->size = curr->size + next->size;
+				curr->next_entr = next->next_entr;
+				cpm_dpalloc_data_init(next);
+			} else {
+				curr = next;
+			}
+		 }
+	}
+
+	return retloc;
+}
+
+/* Remove element from dynamic list of DPRAM
+ */
+static int cpm_dpalloc_rem(cpm_dpalloc_entry_t ** head, cpm_dpalloc_entry_t * ptr)
+{
+	cpm_dpalloc_entry_t	* prev;
+	cpm_dpalloc_entry_t	* curr;
+	int			  retloc;
+
+	retloc = -1;
+	for (prev = NULL , curr = *head;
+	     curr != NULL && ptr != curr;
+	     prev = curr , curr = curr->next_entr)
+		/* EMPTY */ ;
+
+	if (curr) {
+		if (prev) {
+			prev->next_entr = curr->next_entr;
+		} else {
+			*head = curr->next_entr;
+		}
+		retloc = 0;
+	}
+
+	return retloc;
+}
+
+/* Insert element in dynamic list of DPRAM
+ */
+static void cpm_dpalloc_ins(cpm_dpalloc_entry_t ** head, cpm_dpalloc_entry_t * ptr)
+{
+	cpm_dpalloc_entry_t	* prev;
+	cpm_dpalloc_entry_t	* curr;
+
+	for (prev = NULL , curr = *head;
+	     curr != NULL && ptr->start_addr >= curr->start_addr;
+	     prev = curr , curr = curr->next_entr)
+		/* EMPTY */ ;
+
+	ptr->next_entr = curr;
+
+	if (prev) {
+		prev->next_entr = ptr;
+	} else {
+		*head = ptr;
+	}
+}
+/* Allocate some memory from the dual ported ram.  We may want to
+ * enforce alignment restrictions, but right now everyone is a good
+ * citizen.
+ */
+uint m8260_cpm_dpalloc(uint size, uint align)
+{
+    cpm_dpalloc_entry_t   * new_el;
+    cpm_dpalloc_entry_t   * p;
+    cpm_dpalloc_entry_t   * p1;
+    uint			retloc;
+    u_short			max;
+    unsigned long		flags;
+    int			i;
+    uint align_mask;
+    uint off;
+
+    size = (size + 7) & ~7;
+    align_mask = align - 1;
+    max = CPM_DATAONLY_SIZE;
+    retloc = CPM_DP_NOSPACE;
+    new_el = NULL;
+
+    if (size == 0) goto DONE;
+
+    save_flags(flags);
+    cli();
+
+    /* Find free area in DPRAM
+     */
+    for (p = cpm_dpalloc_free; p != NULL; p = p->next_entr) {
+        if (p->size <= max) {
+            off = ((p->start_addr + align_mask) & (~align_mask)) - p->start_addr;
+            if (p->size >= size + off) {
+                new_el = p;
+                max = p->size;
+                retloc = p->start_addr + off;
+            }
+        }
+    }
+
+    if (new_el == NULL) goto DONE1;
+
+    /* Insert new element in the list of allocated DPRAM
+     */
+    p1 = cpm_dpalloc_list;
+    p = NULL;
+    i = 0;
+    while (i < CPM_DPALLOC_COUNT) {
+        if (p1->start_addr == 0 && !p1->size && !p1->next_entr) {
+            p = p1;
+            break;
+        }
+        i ++;
+        p1 ++;
+    }
+
+    if (p == NULL) {
+        panic ("m8xx_cpm_dpalloc: INTERNAL ERROR\n");
+    }
+
+    off = retloc - new_el->start_addr;
+
+    p->start_addr = new_el->start_addr;
+    p->retloc = retloc;
+    p->size = size + off;
+
+    if (new_el->size >  (size+off)) {
+        new_el->size -= (size+off);
+        new_el->start_addr += (size+off);
+        cpm_dpalloc_ins(&cpm_dpalloc_alloc, p);
+    } else {
+        cpm_dpalloc_ins(&cpm_dpalloc_alloc, p);
+        i = cpm_dpalloc_rem(&cpm_dpalloc_free, new_el);
+
+        if ( i == -1) {
+            panic ("m8xx_cpm_dpalloc: INTERNAL ERROR\n");
+        }
+
+        cpm_dpalloc_data_init(new_el);
+    }
+
+ DONE1:
+    restore_flags(flags);
+ DONE:
+    return retloc;
+}
+
+int m8260_cpm_dpfree(uint retloc)
+{
+	cpm_dpalloc_entry_t   * r;
+	int			retval;
+	unsigned long		flags;
+
+	retval = -1;
+
+	if ((retloc < CPM_DATAONLY_BASE) ||
+	    (retloc > CPM_DATAONLY_SIZE + CPM_DATAONLY_BASE)) {
+		goto DONE;
+	}
+
+	save_flags(flags);
+	cli();
+
+	for (r = cpm_dpalloc_alloc;
+	     (r != NULL) && (r->retloc != retloc);
+	     r = r->next_entr)
+		/* EMPTY */ ;
+
+	if (r) {
+		retval = cpm_dpalloc_rem(&cpm_dpalloc_alloc, r);
+
+		if (retval == -1) {
+			panic("m8xx_cpm_dpfree: INTERNAL ERROR\n");
+		}
+		cpm_dpalloc_ins(&cpm_dpalloc_free, r);
+		retval = cpm_dpalloc_cl(cpm_dpalloc_free);
+
+		if (retval == -1) {
+			panic("m8xx_cpm_dpfree: INTERNAL ERROR\n");
+		}
+		retval = 0;
+	} else {
+	  printk(KERN_ERR "m8xx_cpm_dpfree: address not found in alloc list\n");
+	}
+
+	restore_flags(flags);
+DONE:
+	return retval;
+}
+#endif /* DPFREE */
+
 /* We allocate this here because it is used almost exclusively for
  * the communication processor devices.
  */
@@ -50,11 +302,14 @@
 	immr = imp = (volatile immap_t *)IMAP_ADDR;
 	commproc = &imp->im_cpm;
 
+#ifdef DPFREE
+	cpm_dpalloc_init();
+#else
 	/* Reclaim the DP memory for our use.
 	*/
 	dp_alloc_base = CPM_DATAONLY_BASE;
 	dp_alloc_top = dp_alloc_base + CPM_DATAONLY_SIZE;
-
+#endif
 	/* Set the host page for allocation.
 	*/
 	host_buffer =
@@ -68,6 +323,7 @@
 	cpmp = (cpm8260_t *)commproc;
 }
 
+#ifndef DPFREE
 /* Allocate some memory from the dual ported ram.
  * To help protocols with object alignment restrictions, we do that
  * if they ask.
@@ -95,6 +351,12 @@
 
 	return(retloc);
 }
+int m8260_cpm_dpfree(uint start_addr)
+{
+    printk(KERN_ERR "%s() not implemented\n", __FUNCTION__);
+    return -1;
+}
+#endif /*ifndef DPFREE*/
 
 /* We also own one page of host buffer space for the allocation of
  * UART "fifos" and the like.