Add lm32 cpu and milkymist port
[mw/micromonitor-lm32.git] / umon_ports / milkymist / etherdev.c
1 /*
2  * Author: Michael Walle <michael@walle.cc>
3  * License: Lucent Public License 1.02
4  *
5  * Some parts are derived from the milkymist BIOS available at:
6  *   http://github.com/lekernel/milkymist
7  *
8  * The author, namely Sebastien Bourdeauducq, permitted these parts to be
9  * released under the Lucent Public License.
10  */
11
12 #include "config.h"
13 #include "genlib.h"
14 #include "stddefs.h"
15 #include "ether.h"
16 #include "cpuio.h"
17 #include "lm32.h"
18
19 #if INCLUDE_ETHERNET
20
21 #define PKT_BUF_LEN 1512
22
23 static uchar *tx_buf;
24 static uchar *rx_buf;
25 static uchar *rx_buf_back;
26
27 static uchar _buffers[3*PKT_BUF_LEN];
28
29 static struct {
30         ulong tx_pkt;
31         ulong rx_pkt;
32 } stats;
33
34 static uchar preamble_sfd[8] = {0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5};
35 /*
36  * enreset():
37  *      Reset the PHY and MAC.
38  */
39 void
40 enreset(void)
41 {
42         MINIMAC_STATE0 = MINIMAC_STATE_EMPTY;
43         MINIMAC_TXREMAINING = 0;
44         MINIMAC_SETUP = MINIMAC_SETUP_RXRST | MINIMAC_SETUP_TXRST;
45
46         /* TODO: reset phy */
47 }
48
49 /*
50  * eninit():
51  * Initialize the PHY and MAC.
52  * This would include establishing buffer descriptor tables and
53  * all the support code that will be used by the ethernet device.
54  *
55  * It can be assumed at this point that the array uchar BinEnetAddr[6]
56  * contains the 6-byte MAC address.
57  *
58  * Return 0 if successful; else -1.
59  */
60 int
61 eninit(void)
62 {
63         /* Initialize the Phy */
64         /* TODO: init phy */
65
66         /* Query the PHY to determine if the link is up.
67          * If not just default to a 10Base-T, half-duplex interface config.
68          * If link is up, then attempt auto-negotiation.
69          */
70         /* ADD_CODE_HERE */
71
72         /* Init buffers */
73         tx_buf = _buffers;
74         rx_buf = _buffers + PKT_BUF_LEN;
75         rx_buf_back = _buffers + 2*PKT_BUF_LEN;
76
77         /* Set preamble and SFD for the TX buffer */
78         memset(tx_buf, preamble_sfd, sizeof(preamble_sfd));
79
80         /* Initialize the MAC */
81         MINIMAC_ADDR0 = (unsigned int)rx_buf_back;
82         MINIMAC_STATE0 = MINIMAC_STATE_LOADED;
83         MINIMAC_SETUP = 0;
84
85         return (0);
86 }
87
88 int
89 EtherdevStartup(int verbose)
90 {
91         /* Initialize local device error counts (if any) here. */
92         /* OPT_ADD_CODE_HERE */
93
94         /* Put ethernet controller in reset: */
95         enreset();
96
97         /* Initialize controller and return the value returned by
98          * eninit().
99          */
100         return(eninit());
101 }
102
103 /* disablePromiscuousReception():
104  * Provide the code that disables promiscuous reception.
105  */
106 void
107 disablePromiscuousReception(void)
108 {
109         /* minimac doesn't have a mac filter */
110 }
111
112 /* enablePromiscuousReception():
113  * Provide the code that enables promiscuous reception.
114  */
115 void
116 enablePromiscuousReception(void)
117 {
118         /* minimac doesn't have a mac filter */
119 }
120
121 /* disableBroadcastReception():
122  * Provide the code that disables broadcast reception.
123  */
124 void
125 disableBroadcastReception(void)
126 {
127         /* minimac doesn't have a mac filter */
128 }
129
130 /* enableBroadcastReception():
131  * Provide the code that enables broadcast reception.
132  */
133 void
134 enableBroadcastReception(void)
135 {
136         /* minimac doesn't have a mac filter */
137 }
138
139 /* 
140  * enselftest():
141  *      Run a self test of the ethernet device(s).  This can be stubbed
142  *      with a return(1).
143  *      Return 1 if success; else -1 if failure.
144  */
145 int
146 enselftest(int verbose)
147 {
148         return(1);
149 }
150
151 /* ShowEtherdevStats():
152  * This function is used to display device-specific stats (error counts
153  * usually).
154  */
155 void
156 ShowEtherdevStats(void)
157 {
158         /* OPT_ADD_CODE_HERE */
159 }
160
161 /* getXmitBuffer():
162  * Return a pointer to the buffer that is to be used for transmission of
163  * the next packet.  Since the monitor's driver is EXTREMELY basic,
164  * there will only be one packet ever being transmitted.  No need to queue
165  * up transmit packets.
166  */
167 uchar *
168 getXmitBuffer(void)
169 {
170         return(tx_buf + sizeof(preamble_sfd));
171 }
172
173 /* sendBuffer():
174  * Send out the packet assumed to be built in the buffer returned by the
175  * previous call to getXmitBuffer() above.
176  */
177 int
178 sendBuffer(int length)
179 {
180         ulong crc;
181
182         uchar *tx_pkt = tx_buf + sizeof(preamble_sfd);
183
184 #if INCLUDE_ETHERVERBOSE
185         if (EtherVerbose & SHOW_OUTGOING)
186                 printPkt((struct ether_header *)tx_pkt, length, ETHER_OUTGOING);
187 #endif
188
189         /* Bump up the packet length to a minimum of 64 bytes.
190          */
191         if (length < 64)
192                 length = 64;
193
194         /* Add the code that will tickle the device into sending out the
195          * buffer that was previously returned by getXmitBuffer() above...
196          */
197         crc = crc32(tx_pkt, length);
198         tx_pkt[length    ] = (crc & 0xff);
199         tx_pkt[length + 1] = (crc & 0xff00) >> 8;
200         tx_pkt[length + 2] = (crc & 0xff0000) >> 16;
201         tx_pkt[length + 3] = (crc & 0xff000000) >> 24;
202
203         length += 12;
204
205         MINIMAC_TXADDR = (unsigned int) tx_buf;
206         MINIMAC_TXREMAINING = length;
207
208         EtherXFRAMECnt++;
209         return(0);
210 }
211
212 /* DisableEtherdev():
213  * Fine as it is...
214  */
215 void
216 DisableEtherdev(void)
217 {
218         enreset();
219 }
220
221 /* extGetIpAdd():
222  * If there was some external mechanism (other than just using the
223  * IPADD shell variable established in the monrc file) for retrieval of
224  * the board's IP address, then do it here...
225  */
226 char *
227 extGetIpAdd(void)
228 {
229         return((char *)0);
230 }
231
232 /* extGetEtherAdd():
233  * If there was some external mechanism (other than just using the
234  * ETHERADD shell variable established in the monrc file) for retrieval of
235  * the board's MAC address, then do it here...
236  */
237 char *
238 extGetEtherAdd(void)
239 {
240         return((char *)0);
241 }
242
243 /*
244  * polletherdev():
245  * Called continuously by the monitor (ethernet.c) to determine if there
246  * is any incoming ethernet packets.
247  *
248  * NOTES:
249  * 1. This function must be reentrant, because there are a few cases in
250  *    processPACKET() where pollethernet() may be called.
251  * 2. It should only process one packet per call.  This is important
252  *    because if allowed to stay here to flush all available packets,
253  *    it may starve the rest of the system (especially in cases of heavy
254  *    network traffic).
255  * 3. There are cases in the monitor's execution that may cause the
256  *    polling polletherdev() to cease for several seconds.  Depending on
257  *    network traffic, this may cause the input buffering mechanism on
258  *    the ethernet device to overflow.  A robust polletherdev() function
259  *    should support this gracefully (i.e. when the error is detected,
260  *    attempt to pass all queued packets to processPACKET(), then do what
261  *    is necessary to clear the error).
262  */
263 int
264 polletherdev(void)
265 {
266         uchar *pktbuf = (uchar *)0;
267         uchar *buf;
268         int     pktlen = 0, pktcnt = 0;
269
270         if (MINIMAC_STATE0 == MINIMAC_STATE_PENDING) {
271                 lm32_flush_dcache();
272                                 
273                 pktbuf = rx_buf_back + 8;
274                 pktlen = MINIMAC_COUNT0 - 8;
275
276                 /* switch rx buffers */
277                 buf = rx_buf;
278                 rx_buf = rx_buf_back;
279                 rx_buf_back = buf;
280
281                 MINIMAC_ADDR0 = (unsigned int)rx_buf_back;
282                 MINIMAC_STATE0 = MINIMAC_STATE_LOADED;
283
284                 printPkt((struct ether_header *)pktbuf, pktlen, ETHER_INCOMING);
285                 
286                 processPACKET((struct ether_header *)pktbuf, pktlen);
287                 pktcnt++;
288                 //MINIMAC_STATE0 = MINIMAC_STATE_LOADED;
289         }
290         return(pktcnt);
291 }
292
293 #endif