1 | /*
|
---|
2 | ** File: netbuff.c Jun. 10, 2000
|
---|
3 | **
|
---|
4 | ** Author: Giovanni Falzoni <gfalzoni@inwind.it>
|
---|
5 | **
|
---|
6 | ** This file contains specific implementation of buffering
|
---|
7 | ** for network packets.
|
---|
8 | **
|
---|
9 | ** $Id: netbuff.c,v 1.3 2005/08/05 19:08:43 beng Exp $
|
---|
10 | */
|
---|
11 |
|
---|
12 | #include "drivers.h"
|
---|
13 | #include <net/gen/ether.h>
|
---|
14 | #include <net/gen/eth_io.h>
|
---|
15 | #include "dp.h"
|
---|
16 |
|
---|
17 | #if (HAVE_BUFFERS == 1)
|
---|
18 |
|
---|
19 | static m_hdr_t *allocptr = NULL;
|
---|
20 | static char tx_rx_buff[8192];
|
---|
21 |
|
---|
22 | /*
|
---|
23 | ** Name: void *alloc_buff(dpeth_t *dep, int size)
|
---|
24 | ** Function: Allocates a buffer from the common pool.
|
---|
25 | */
|
---|
26 | PUBLIC void *alloc_buff(dpeth_t *dep, int size)
|
---|
27 | {
|
---|
28 | m_hdr_t *ptr, *wrk = allocptr;
|
---|
29 | int units = ((size + sizeof(m_hdr_t) - 1) / sizeof(m_hdr_t)) + 1;
|
---|
30 |
|
---|
31 | lock();
|
---|
32 | for (ptr = wrk->next;; wrk = ptr, ptr = ptr->next) {
|
---|
33 | if (ptr->size >= units) {
|
---|
34 | /* Memory is available, carve requested size from pool */
|
---|
35 | if (ptr->size == units) {
|
---|
36 | wrk->next = ptr->next;
|
---|
37 | } else {
|
---|
38 | /* Get memory from top address */
|
---|
39 | ptr->size -= units;
|
---|
40 | ptr += ptr->size;
|
---|
41 | ptr->size = units;
|
---|
42 | }
|
---|
43 | allocptr = wrk;
|
---|
44 | unlock();
|
---|
45 | return ptr + 1;
|
---|
46 | }
|
---|
47 | if (ptr == allocptr) break;
|
---|
48 | }
|
---|
49 | unlock();
|
---|
50 | return NULL; /* No memory available */
|
---|
51 | }
|
---|
52 |
|
---|
53 | /*
|
---|
54 | ** Name: void free_buff(dpeth_t *dep, void *blk)
|
---|
55 | ** Function: Returns a buffer to the common pool.
|
---|
56 | */
|
---|
57 | PUBLIC void free_buff(dpeth_t *dep, void *blk)
|
---|
58 | {
|
---|
59 | m_hdr_t *wrk, *ptr = (m_hdr_t *) blk - 1;
|
---|
60 |
|
---|
61 | lock(); /* Scan linked list for the correct place */
|
---|
62 | for (wrk = allocptr; !(ptr > wrk && ptr < wrk->next); wrk = wrk->next)
|
---|
63 | if (wrk >= wrk->next && (ptr > wrk || ptr < wrk->next)) break;
|
---|
64 |
|
---|
65 | /* Check if adjacent block is free and join blocks */
|
---|
66 | if (ptr + ptr->size == wrk->next) {
|
---|
67 | ptr->size += wrk->next->size;
|
---|
68 | ptr->next = wrk->next->next;
|
---|
69 | } else
|
---|
70 | ptr->next = wrk->next;
|
---|
71 | if (wrk + wrk->size == ptr) {
|
---|
72 | wrk->size += ptr->size;
|
---|
73 | wrk->next = ptr->next;
|
---|
74 | } else
|
---|
75 | wrk->next = ptr;
|
---|
76 | allocptr = wrk; /* Point allocptr to block just released */
|
---|
77 | unlock();
|
---|
78 | return;
|
---|
79 | }
|
---|
80 |
|
---|
81 | /*
|
---|
82 | ** Name: void init_buff(dpeth_t *dep, buff_t **tx_buff)
|
---|
83 | ** Function: Initalizes driver data structures.
|
---|
84 | */
|
---|
85 | PUBLIC void init_buff(dpeth_t *dep, buff_t **tx_buff)
|
---|
86 | {
|
---|
87 |
|
---|
88 | /* Initializes buffer pool */
|
---|
89 | if (allocptr == NULL) {
|
---|
90 | m_hdr_t *rx = (m_hdr_t *) tx_rx_buff;
|
---|
91 | rx->next = allocptr = rx;
|
---|
92 | rx->size = 0;
|
---|
93 | rx += 1;
|
---|
94 | rx->next = NULL;
|
---|
95 | rx->size = (sizeof(tx_rx_buff) / sizeof(m_hdr_t)) - 1;
|
---|
96 | free_buff(dep, rx + 1);
|
---|
97 | dep->de_recvq_tail = dep->de_recvq_head = NULL;
|
---|
98 | if (tx_buff != NULL) {
|
---|
99 | *tx_buff = alloc_buff(dep, ETH_MAX_PACK_SIZE + sizeof(buff_t));
|
---|
100 | (*tx_buff)->size = 0;
|
---|
101 | }
|
---|
102 | }
|
---|
103 | return; /* Done */
|
---|
104 | }
|
---|
105 |
|
---|
106 | /*
|
---|
107 | ** Name: void mem2user(dpeth_t *dep, buff_t *rxbuff);
|
---|
108 | ** Function: Copies a packet from local buffer to user area.
|
---|
109 | */
|
---|
110 | PUBLIC void mem2user(dpeth_t *dep, buff_t *rxbuff)
|
---|
111 | {
|
---|
112 | phys_bytes phys_user;
|
---|
113 | int bytes, ix = 0;
|
---|
114 | iovec_dat_t *iovp = &dep->de_read_iovec;
|
---|
115 | int pktsize = rxbuff->size;
|
---|
116 | char *buffer = rxbuff->buffer;
|
---|
117 |
|
---|
118 | do { /* Reads chuncks of packet into user buffers */
|
---|
119 |
|
---|
120 | bytes = iovp->iod_iovec[ix].iov_size; /* Size of buffer */
|
---|
121 | if (bytes > pktsize) bytes = pktsize;
|
---|
122 |
|
---|
123 | /* Reads from Rx buffer to user area */
|
---|
124 | sys_datacopy(SELF, (vir_bytes)buffer, iovp->iod_proc_nr,
|
---|
125 | iovp->iod_iovec[ix].iov_addr, bytes);
|
---|
126 | buffer += bytes;
|
---|
127 |
|
---|
128 | if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
|
---|
129 | dp_next_iovec(iovp);
|
---|
130 | ix = 0;
|
---|
131 | }
|
---|
132 | /* Till packet done */
|
---|
133 | } while ((pktsize -= bytes) > 0);
|
---|
134 | return;
|
---|
135 | }
|
---|
136 |
|
---|
137 | /*
|
---|
138 | ** Name: void user2mem(dpeth_t *dep, buff_t *txbuff)
|
---|
139 | ** Function: Copies a packet from user area to local buffer.
|
---|
140 | */
|
---|
141 | PUBLIC void user2mem(dpeth_t *dep, buff_t *txbuff)
|
---|
142 | {
|
---|
143 | phys_bytes phys_user;
|
---|
144 | int bytes, ix = 0;
|
---|
145 | iovec_dat_t *iovp = &dep->de_write_iovec;
|
---|
146 | int pktsize = txbuff->size;
|
---|
147 | char *buffer = txbuff->buffer;
|
---|
148 |
|
---|
149 | do { /* Reads chuncks of packet from user buffers */
|
---|
150 |
|
---|
151 | bytes = iovp->iod_iovec[ix].iov_size; /* Size of buffer */
|
---|
152 | if (bytes > pktsize) bytes = pktsize;
|
---|
153 | sys_datacopy(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr,
|
---|
154 | SELF, (vir_bytes)buffer, bytes);
|
---|
155 | buffer += bytes;
|
---|
156 |
|
---|
157 | if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
|
---|
158 | dp_next_iovec(iovp);
|
---|
159 | ix = 0;
|
---|
160 | }
|
---|
161 | /* Till packet done */
|
---|
162 | } while ((pktsize -= bytes) > 0);
|
---|
163 | return;
|
---|
164 | }
|
---|
165 |
|
---|
166 | #endif /* HAVE_BUFFERS */
|
---|
167 |
|
---|
168 | /** netbuff.c **/
|
---|