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 #include +#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.