patch-2.3.42 linux/arch/sparc/ap1000/tnet.c
Next file: linux/arch/sparc/ap1000/util.c
Previous file: linux/arch/sparc/ap1000/timer.c
Back to the patch index
Back to the overall index
- Lines: 709
- Date:
Wed Dec 31 16:00:00 1969
- Orig file:
v2.3.41/linux/arch/sparc/ap1000/tnet.c
- Orig date:
Tue Aug 4 16:03:34 1998
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/ap1000/tnet.c linux/arch/sparc/ap1000/tnet.c
@@ -1,708 +0,0 @@
- /*
- * Copyright 1996 The Australian National University.
- * Copyright 1996 Fujitsu Laboratories Limited
- *
- * This software may be distributed under the terms of the Gnu
- * Public License version 2 or later
- */
-/* routines to control the AP1000 Tnet interface */
-
-#include <asm/ap1000/apreg.h>
-#include <asm/ap1000/aplib.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <asm/pgtable.h>
-#include <asm/pgtsrmmu.h>
-#include <stdarg.h>
-#include <linux/skbuff.h>
-
-
-/* message types for system messages */
-#define TNET_IP 0
-#define TNET_IP_SMALL 1
-#define TNET_RPC 2
-
-static struct {
- int errors;
- int alloc_errors;
- int bytes_received;
- int bytes_sent;
- int packets_received;
- int packets_sent;
- int small_packets_received;
- int small_packets_sent;
-} tnet_stats;
-
-extern int cap_cid0;
-extern int cap_ncel0;
-static u_long xy_global_head;
-
-extern unsigned _ncel, _ncelx, _ncely, _cid, _cidx, _cidy;
-
-extern struct ringbuf_struct system_ringbuf;
-extern u_long system_read_ptr;
-
-u_long system_recv_flag = 0;
-static u_long system_recv_count = 0;
-
-int *tnet_rel_cid_table;
-
-static int dummy=1;
-
-#define TNET_IP_THRESHOLD 100
-
-void tnet_check_completion(void);
-static void reschedule(void);
-static u_long tnet_add_completion(void (*fn)(int a1,...),
- int a1,int a2);
-static void tnet_info(void);
-
-static struct {
- int shift;
- void (*fn)(void);
-} iports[4] = {
- {MC_INTP_0_SH,tnet_check_completion},
- {MC_INTP_1_SH,reschedule},
- {MC_INTP_2_SH,NULL},
- {MC_INTP_3_SH,NULL}};
-
-static inline int rel_cid(unsigned dst)
-{
- unsigned dstx, dsty;
- unsigned dx,dy;
-
- if (dst == _cid) return 0;
-
- dstx = dst % _ncelx;
- dsty = dst / _ncelx;
- if (dstx >= _cidx)
- dx = dstx - _cidx;
- else
- dx = (_ncelx - _cidx) + dstx;
-
- if (dsty >= _cidy)
- dy = dsty - _cidy;
- else
- dy = (_ncely - _cidy) + dsty;
-
- return (dx<<8) | dy;
-}
-
-#define SAVE_PID() \
- unsigned long flags; \
- int saved_pid; \
- save_flags(flags); cli(); \
- saved_pid = MSC_IN(MSC_PID); \
- MSC_OUT(MSC_PID,SYSTEM_CONTEXT);
-
-#define RESTORE_PID() \
- MSC_OUT(MSC_PID,saved_pid); \
- restore_flags(flags);
-
-
-void ap_put(int dest_cell,u_long local_addr,int size,
- u_long remote_addr,u_long dest_flag,u_long local_flag)
-{
- volatile u_long *entry;
- SAVE_PID();
-
- entry = (volatile u_long *)MSC_PUT_QUEUE_S;
-
- *entry = tnet_rel_cid_table[dest_cell];
- *entry = ((size+3) >> 2);
- *entry = (u_long)remote_addr;
- *entry = 0;
- *entry = (u_long)dest_flag;
- *entry = (u_long)local_flag;
- *entry = (u_long)local_addr;
- *entry = 0;
- RESTORE_PID();
-}
-
-/* remote_addr is physical
- local address is virtual
- both flags are virtual */
-void ap_phys_put(int dest_cell,u_long local_addr,int size,
- u_long remote_addr,u_long dest_flag,u_long local_flag)
-{
- volatile u_long *entry;
- SAVE_PID();
-
- entry = (volatile u_long *)MSC_CPUT_QUEUE_S;
-
- *entry = tnet_rel_cid_table[dest_cell];
- *entry = ((size+3) >> 2);
- *entry = (u_long)remote_addr;
- *entry = 0;
- *entry = (u_long)dest_flag;
- *entry = (u_long)local_flag;
- *entry = (u_long)local_addr;
- *entry = 0;
- RESTORE_PID();
-}
-
-
-/* broadcast put - yeah! */
-void ap_bput(u_long local_addr,int size,
- u_long remote_addr,u_long dest_flag,u_long local_flag)
-{
- volatile u_long *entry = (volatile u_long *)MSC_XYG_QUEUE_S;
- SAVE_PID();
-
- *entry = xy_global_head;
- *entry = ((size+3) >> 2);
- *entry = (u_long)remote_addr;
- *entry = 0;
- *entry = (u_long)dest_flag;
- *entry = (u_long)local_flag;
- *entry = (u_long)local_addr;
- *entry = 0;
- RESTORE_PID();
-}
-
-
-/* remote_addr is physical */
-void ap_phys_bput(u_long local_addr,int size,
- u_long remote_addr,u_long dest_flag,u_long local_flag)
-{
- volatile u_long *entry = (volatile u_long *)MSC_CXYG_QUEUE_S;
- SAVE_PID();
-
- *entry = xy_global_head;
- *entry = ((size+3) >> 2);
- *entry = (u_long)remote_addr;
- *entry = 0;
- *entry = (u_long)dest_flag;
- *entry = (u_long)local_flag;
- *entry = (u_long)local_addr;
- *entry = 0;
- RESTORE_PID();
-}
-
-
-
-void ap_get(int dest_cell,u_long local_addr,int size,
- u_long remote_addr,u_long local_flag,u_long dest_flag)
-{
- volatile u_long *entry;
- SAVE_PID();
-
- entry = (u_long *)MSC_GET_QUEUE_S;
-
- *entry = tnet_rel_cid_table[dest_cell];
- *entry = (size+3) >> 2; /* byte --> word */
- *entry = (u_long)local_addr;
- *entry = 0;
- *entry = (u_long)local_flag;
- *entry = (u_long)dest_flag;
- *entry = (u_long)remote_addr;
- *entry = 0;
- RESTORE_PID();
-}
-
-
-/* local_addr is physical
- remote_addr is virtual
- both flags are virtual
-*/
-void ap_phys_get(int dest_cell,u_long local_addr,int size,
- u_long remote_addr,u_long local_flag,u_long dest_flag)
-{
- volatile u_long *entry;
- SAVE_PID();
-
- entry = (u_long *)MSC_CGET_QUEUE_S;
-
- *entry = tnet_rel_cid_table[dest_cell];
- *entry = (size+3) >> 2; /* byte --> word */
- *entry = (u_long)local_addr;
- *entry = 0;
- *entry = (u_long)local_flag;
- *entry = (u_long)dest_flag;
- *entry = (u_long)remote_addr;
- *entry = 0;
- RESTORE_PID();
-}
-
-
-/*
- * copy a message from the ringbuffer - being careful of wraparound
-*/
-static inline void tnet_copyin(unsigned *dest,unsigned *src,int size)
-{
- unsigned *limit = (unsigned *)system_ringbuf.ringbuf +
- (SYSTEM_RINGBUF_SIZE>>2);
- int size1 = limit - src;
-
- if (size < size1)
- size1 = size;
-
- size -= size1;
- while (size1--) {
- *dest++ = *src++;
- }
- src = system_ringbuf.ringbuf;
- while (size--) {
- *dest++ = *src++;
- }
-}
-
-
-/*
- put some data into a tasks ringbuffer. size is in words.
- */
-static inline void memcpy_to_rbuf(unsigned tid,unsigned *msgp,unsigned size)
-{
- struct aplib_struct *aplib;
- unsigned octx, ctx;
- struct task_struct *tsk;
- unsigned room;
-
- tsk = task[tid];
- if (!tsk || !tsk->aplib)
- return;
-
- octx = srmmu_get_context();
- ctx = MPP_TASK_TO_CTX(tid);
- if (octx != ctx)
- srmmu_set_context(ctx);
- aplib = tsk->aplib;
-
- if (aplib->write_pointer < aplib->read_pointer)
- room = aplib->read_pointer - (aplib->write_pointer+1);
- else
- room = aplib->ringbuf_size -
- ((aplib->write_pointer+1)-aplib->read_pointer);
-
- if (room < size) {
- send_sig(SIGLOST,tsk,1);
- goto finished;
- }
-
- tnet_copyin(&aplib->ringbuf[aplib->write_pointer], msgp, size);
-
- aplib->write_pointer += size;
- if (aplib->write_pointer >= aplib->ringbuf_size)
- aplib->write_pointer -= aplib->ringbuf_size;
-
- aplib->rbuf_flag1++;
-
-finished:
- if (octx != ctx)
- srmmu_set_context(octx);
-}
-
-
-
-/* a aplib message has arrived on the system message queue - process
- it immediately and return the number of bytes taken by the message in
- the system ringbuffer
-
- Note that this function may be called from interrupt level
- */
-static inline void aplib_system_recv(unsigned *msgp)
-{
- unsigned tag = msgp[1]>>28;
- unsigned size, tid;
-
- if (tag == RBUF_BIGSEND) {
- aplib_bigrecv(msgp);
- return;
- }
-
- size = (msgp[0]&0xFFFFF);
- tid = (msgp[1]&0x3FF);
-
- memcpy_to_rbuf(tid,msgp,size+2);
-}
-
-
-void tnet_ip_complete(struct sk_buff *skb,int from)
-{
-#if IP_DEBUG
- char *data = skb->data;
- int i;
- printk("CID(%d) tnet ip complete from %d\n",_cid,from);
-
- for (i=0;i<skb->len;i+=4)
- printk("(%08x)%c",*(int *)(data+i),i==32?'\n':' ');
- printk("\n");
-#endif
- /* ap_phys_put(from,(u_long)&dummy,4,MC_INTP_0,0,0); */
- bif_rx(skb);
- tnet_stats.bytes_received += skb->len;
- tnet_stats.packets_received++;
-}
-
-
-static void tnet_ip_recv(int cid,u_long *info)
-{
- u_long flag;
- u_long ipsize = info[1];
- u_long remote_addr = info[0];
- u_long remote_flag = info[2];
- struct sk_buff *skb = dev_alloc_skb(ipsize+8);
- char *p;
-
- if (!skb) {
- ap_put(cid,0,0,0,remote_flag,0);
- ap_phys_put(cid,(u_long)&dummy,4,MC_INTP_0,0,0);
- tnet_stats.alloc_errors++;
- return;
- }
-
- skb_reserve(skb,8); /* align on 16 byte boundary */
-
- flag = tnet_add_completion(tnet_ip_complete,(int)skb,(int)cid);
-
- p = (char *)skb_put(skb,ipsize);
-#if 0
-{
- static unsigned count=0;
- if (count%500 == 0)
- printk("CID(%d) fetching %d bytes from %x to %x\n",
- _cid,ipsize,remote_addr,p);
- count++;
-}
-#endif
- ap_get(cid,p,ipsize,remote_addr,flag,remote_flag);
- ap_phys_get(cid,MC_INTP_0,4,(u_long)&dummy,0,0);
-#if IP_DEBUG
- printk("CID(%d) ip packet of length %ld from %ld\n",_cid,ipsize,cid);
-#endif
-}
-
-
-static void tnet_ip_recv_small(u_long *data,int size)
-{
- struct sk_buff *skb = dev_alloc_skb(size+8);
- if (skb) {
- skb_reserve(skb,8);
- tnet_copyin((unsigned *)skb_put(skb,size),(unsigned *)data,(size+3)>>2);
- bif_rx(skb);
- tnet_stats.bytes_received += size;
- tnet_stats.packets_received++;
- tnet_stats.small_packets_received++;
- } else {
- tnet_stats.alloc_errors++;
- }
-}
-
-
-/* we've got an RPC from a remote cell */
-static void tnet_rpc_recv(u_long *data,int size)
-{
- struct fnp {
- void (*fn)();
- } fnp;
- fnp = *(struct fnp *)data;
- fnp.fn(data,size);
-}
-
-/*
- * receive messages from the system ringbuffer. We don't bother with
- * all the niceities that are done in user space, we just always
- * process the messages in order
- */
-static inline void tnet_recv(void)
-{
- unsigned flags;
- u_long from,*data,fix,align,size1,size,type;
-
- if (system_recv_flag == system_recv_count)
- return;
-
- save_flags(flags); cli();
- while (system_recv_flag != system_recv_count) {
- u_long read_ptr =
- (system_read_ptr + 1) % (SYSTEM_RINGBUF_SIZE>>5);
- u_long *msgp =
- ((u_long *)system_ringbuf.ringbuf) + (read_ptr<<3);
- u_long tag = (msgp[1]>>28) & 0xF;
- size1 = (msgp[0]&0xFFFFF)<<2;
-
- /* move our read pointer past this message */
- system_read_ptr = (system_read_ptr +
- ((size1+8+31)>>5))%(SYSTEM_RINGBUF_SIZE>>5);
- system_recv_count++;
-
-
- if (tag != RBUF_SYSTEM) {
- aplib_system_recv(msgp);
- continue;
- }
-
- from = msgp[0] >> 22;
- data = msgp+2;
- fix = (msgp[0]>>20)&3;
- align = (msgp[1]>>26)&3;
- size = ((size1 - align) & ~3) | fix;
- type = (msgp[1]&0xFF);
-
- switch (type) {
- case TNET_IP:
- tnet_ip_recv(from,data);
- break;
-
- case TNET_IP_SMALL:
- tnet_ip_recv_small(data,size);
- break;
-
- case TNET_RPC:
- tnet_rpc_recv(data,size);
- break;
-
- default:
- tnet_stats.errors++;
- printk("unknown Tnet type %ld\n",type);
- }
-
-#if DEBUG
- printk("CID(%d) recvd %d bytes of type %d read_ptr=%x\n",
- _cid,size,type,system_read_ptr);
-#endif
- }
- restore_flags(flags);
-}
-
-
-#define COMPLETION_LIST_LENGTH 256
-
-static unsigned completion_list_rp = 0;
-static unsigned completion_list_wp = 0;
-
-static volatile struct completion_struct {
- u_long flag;
- void (*fn)(int a1,...);
- u_long args[2];
-} completion_list[COMPLETION_LIST_LENGTH];
-
-
-void tnet_check_completion(void)
-{
- struct completion_struct *cs;
- unsigned flags;
-
- tnet_recv();
-
- if (completion_list[completion_list_rp].flag != 2)
- return;
-
- save_flags(flags); cli();
-
- while (completion_list[completion_list_rp].flag == 2) {
- cs = &completion_list[completion_list_rp];
- cs->flag = 0;
- if (++completion_list_rp == COMPLETION_LIST_LENGTH)
- completion_list_rp = 0;
-
- restore_flags(flags);
-
- cs->fn(cs->args[0],cs->args[1]);
-
- if (completion_list[completion_list_rp].flag != 2)
- return;
-
- save_flags(flags); cli();
- }
-
- restore_flags(flags);
-}
-
-
-static u_long tnet_add_completion(void (*fn)(int a1,...),int a1,int a2)
-{
- unsigned flags;
- struct completion_struct *cs;
-
- save_flags(flags); cli();
-
- while (completion_list[completion_list_wp].flag != 0)
- tnet_check_completion();
-
- cs = &completion_list[completion_list_wp];
-
- if (++completion_list_wp == COMPLETION_LIST_LENGTH)
- completion_list_wp = 0;
-
- restore_flags(flags);
-
- cs->flag = 1;
- cs->fn = fn;
- cs->args[0] = a1;
- cs->args[1] = a2;
-
- return (u_long)&cs->flag;
-}
-
-
-/*
- * send a message to the tnet ringuffer on another cell. When the send has
- * completed call fn with the args supplied
- */
-static void tnet_send(long cid,long type,char *src_addr,long byteSize,
- int immediate,u_long flag)
-{
- int wordSize;
- int byteAlign, byteFix;
- u_long src;
- u_long info1, info2;
- volatile u_long *entry = (volatile u_long *)MSC_SEND_QUEUE_S;
- SAVE_PID();
-
- byteAlign = ((u_long)src_addr) & 0x3;
- byteFix = byteSize & 0x3;
-
- src = (u_long)src_addr & ~3;
-
- wordSize = (byteSize + byteAlign + 3) >> 2;
-
- info1 = (_cid << 22) | (byteFix << 20) | wordSize;
- info2 = (RBUF_SYSTEM<<28) | (byteAlign << 26) | type;
-
- *entry = tnet_rel_cid_table[cid];
- *entry = wordSize;
- *entry = (u_long)&system_recv_flag;
- *entry = flag;
- *entry = (u_long)src;
- *entry = 0;
- *entry = info1;
- *entry = info2;
- RESTORE_PID();
-
- ap_phys_put(cid,(u_long)&dummy,4,MC_INTP_0,0,0);
- if (immediate && flag)
- ap_phys_put(_cid,(u_long)&dummy,4,MC_INTP_0,0,0);
-}
-
-
-static void free_skb(struct sk_buff *skb, int op)
-{
- dev_kfree_skb(skb);
-}
-
-void tnet_send_ip(int cid,struct sk_buff *skb)
-{
- char *data = skb->data + sizeof(struct cap_request);
- int size = skb->len - sizeof(struct cap_request);
- u_long flag;
-#if IP_DEBUG
- int i;
- for (i=0;i<size;i+=4)
- printk("[%08x]%c",*(int *)(data+i),i==32?'\n':' ');
- printk("\n");
-#endif
- if (size > TNET_IP_THRESHOLD) {
- int *info = (int *)skb->data; /* re-use the header */
- info[0] = (int)data;
- info[1] = size;
- info[2] = tnet_add_completion(free_skb, (int)skb, 0);
- tnet_send(cid,TNET_IP,info,sizeof(int)*3,0,0);
- } else {
- flag = tnet_add_completion(free_skb, (int)skb, 0);
- tnet_send(cid,TNET_IP_SMALL,data,size,0,flag);
- tnet_stats.small_packets_sent++;
- }
- tnet_stats.packets_sent++;
- tnet_stats.bytes_sent += size;
-#if IP_DEBUG
- printk("CID(%d) sent IP of size %d to %d\n",_cid,size,cid);
-#endif
-}
-
-static void reschedule(void)
-{
- current->need_resched = 1;
- mark_bh(TQUEUE_BH);
-}
-
-
-/* make a remote procedure call
- If free is set then free the data after sending it
- The first element of data is presumed to be a function pointer
-*/
-int tnet_rpc(int cell,char *data,int size,int free)
-{
- unsigned flag=0;
-
- if (free) {
- flag = tnet_add_completion(kfree,data,0);
- }
-
- tnet_send(cell,TNET_RPC,data,size,0,flag);
- return 0;
-}
-
-
-static void iport_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
- int i;
- u_long intr = MC_IN(MC_INTR_PORT);
-
- for (i=0;i<4;i++) {
- if (intr & (AP_INTR_REQ << iports[i].shift)) {
- MC_OUT(MC_INTR_PORT,AP_CLR_INTR_REQ << iports[i].shift);
- if (iports[i].fn) iports[i].fn();
- }
- }
-}
-
-
-void ap_tnet_init(void)
-{
- int i;
-
- bif_add_debug_key('T',tnet_info,"Tnet status");
-
- memset(completion_list,0,sizeof(completion_list));
-
- request_irq(APIPORT_IRQ, iport_irq, SA_INTERRUPT, "iport", 0);
-
- for (i=0;i<4;i++) {
- MC_OUT(MC_INTR_PORT,AP_CLR_INTR_REQ << iports[i].shift);
- MC_OUT(MC_INTR_PORT,AP_CLR_INTR_MASK << iports[i].shift);
- }
-
-
- tnet_rel_cid_table = (int *)kmalloc(sizeof(int)*_ncel,GFP_ATOMIC);
- for (i=0;i<_ncel;i++)
- tnet_rel_cid_table[i] = rel_cid(i);
-
- if(_cid == 0) {
- xy_global_head = (((_ncelx -1) << 8) & 0xff00) |
- ((_ncely - 1) & 0xff);
- }
- else {
- for(i = 1; i < _ncel; i *= 2){
- if(i & _cid) {
- int rcidx = (_cid-i)%_ncelx - _cid%_ncelx;
- int rcidy = (_cid-i)/_ncelx - _cid/_ncelx;
- xy_global_head = ((rcidx << 8) & 0xff00) |
- (rcidy & 0xff);
- break;
- }
- }
- }
-}
-
-static void tnet_info(void)
-{
- struct completion_struct *cs;
-
- printk(
- "errors=%d alloc_errors=%d
-bytes_received=%d bytes_sent=%d
-packets_received=%d packets_sent=%d
-small_received=%d small_sent=%d
-",
- tnet_stats.errors, tnet_stats.alloc_errors,
- tnet_stats.bytes_received,
- tnet_stats.bytes_sent, tnet_stats.packets_received,
- tnet_stats.packets_sent, tnet_stats.small_packets_received,
- tnet_stats.small_packets_sent);
-
- printk("recv_flag=%d recv_count=%d read_ptr=%d\n",
- system_recv_flag,system_recv_count,system_read_ptr);
- printk("completion_list_rp=%d completion_list_wp=%d\n",
- completion_list_rp,completion_list_wp);
-}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)