1 /* ===================================================================================
2 * Copyright (c) <2009> Synopsys, Inc.
3 * SPDX-License-Identifier: Apache-2.0
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
6 * this software annotated with this license and associated documentation files
7 * (the "Software"), to deal in the Software without restriction, including without
8 * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
17 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
20 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * =================================================================================== */
23
24
25 /** \file
26 * This is the network dependent layer to handle network related functionality.
27 * This file is tightly coupled to neworking frame work of linux 2.6.xx kernel.
28 * The functionality carried out in this file should be treated as an example only
29 * if the underlying operating system is not Linux.
30 *
31 * \note Many of the functions other than the device specific functions
32 * changes for operating system other than Linux 2.6.xx
33 * \internal
34 *-----------------------------REVISION HISTORY-----------------------------------
35 * Synopsys 01/Aug/2007 Created
36 */
37
38 #include "string.h"
39 #include "synopGMAC_network_interface.h"
40
41
42 synopGMACdevice GMACdev[GMAC_CNT];
43 static DmaDesc tx_desc[GMAC_CNT][TRANSMIT_DESC_SIZE] __attribute__ ((aligned (64)));
44 static DmaDesc rx_desc[GMAC_CNT][RECEIVE_DESC_SIZE] __attribute__ ((aligned (64)));
45
46 //static struct sk_buff tx_buf[GMAC_CNT][TRANSMIT_DESC_SIZE] __attribute__ ((aligned (64)));
47 //static struct sk_buff rx_buf[GMAC_CNT][RECEIVE_DESC_SIZE] __attribute__ ((aligned (64)));
48 struct sk_buff tx_buf[GMAC_CNT][TRANSMIT_DESC_SIZE] __attribute__ ((aligned (64)));
49 struct sk_buff rx_buf[GMAC_CNT][RECEIVE_DESC_SIZE] __attribute__ ((aligned (64)));
50
51 // These 2 are accessable from application
52 struct sk_buff txbuf[GMAC_CNT] __attribute__ ((aligned (64))); // set align to separate cacheable and non-cacheable data to different cache line.
53 struct sk_buff rxbuf[GMAC_CNT] __attribute__ ((aligned (64)));
54
55 u8 mac_addr0[6] = DEFAULT_MAC0_ADDRESS;
56 u8 mac_addr1[6] = DEFAULT_MAC1_ADDRESS;
57
58 //static struct timer_list synopGMAC_cable_unplug_timer;
59 //static u32 GMAC_Power_down; // This global variable is used to indicate the ISR whether the interrupts occured in the process of powering down the mac or not
60
61
62 /**
63 * Function used to detect the cable plugging and unplugging.
64 * This function gets scheduled once in every second and polls
65 * the PHY register for network cable plug/unplug. Once the
66 * connection is back the GMAC device is configured as per
67 * new Duplex mode and Speed of the connection.
68 * @param[in] u32 type but is not used currently.
69 * \return returns void.
70 * \note This function is tightly coupled with Linux 2.6.xx.
71 * \callgraph
72 */
73
74
75
synopGMAC_powerdown_mac(synopGMACdevice * gmacdev)76 void synopGMAC_powerdown_mac(synopGMACdevice *gmacdev)
77 {
78 TR0("Put the GMAC to power down mode..\n");
79 // Disable the Dma engines in tx path
80 gmacdev->GMAC_Power_down = 1; // Let ISR know that Mac is going to be in the power down mode
81 synopGMAC_disable_dma_tx(gmacdev);
82 plat_delay(10000); //allow any pending transmission to complete
83 // Disable the Mac for both tx and rx
84 synopGMAC_tx_disable(gmacdev);
85 synopGMAC_rx_disable(gmacdev);
86 plat_delay(10000); //Allow any pending buffer to be read by host
87 //Disable the Dma in rx path
88 synopGMAC_disable_dma_rx(gmacdev);
89
90 //enable the power down mode
91 //synopGMAC_pmt_unicast_enable(gmacdev);
92
93 //prepare the gmac for magic packet reception and wake up frame reception
94 synopGMAC_magic_packet_enable(gmacdev);
95
96 //gate the application and transmit clock inputs to the code. This is not done in this driver :).
97
98 //enable the Mac for reception
99 synopGMAC_rx_enable(gmacdev);
100
101 //Enable the assertion of PMT interrupt
102 synopGMAC_pmt_int_enable(gmacdev);
103 //enter the power down mode
104 synopGMAC_power_down_enable(gmacdev);
105 return;
106 }
107
synopGMAC_powerup_mac(synopGMACdevice * gmacdev)108 void synopGMAC_powerup_mac(synopGMACdevice *gmacdev)
109 {
110 gmacdev->GMAC_Power_down = 0; // Let ISR know that MAC is out of power down now
111 if( synopGMAC_is_magic_packet_received(gmacdev))
112 TR("GMAC wokeup due to Magic Pkt Received\n");
113 if(synopGMAC_is_wakeup_frame_received(gmacdev))
114 TR("GMAC wokeup due to Wakeup Frame Received\n");
115 //Disable the assertion of PMT interrupt
116 synopGMAC_pmt_int_disable(gmacdev);
117 //Enable the mac and Dma rx and tx paths
118 synopGMAC_rx_enable(gmacdev);
119 synopGMAC_enable_dma_rx(gmacdev);
120
121 synopGMAC_tx_enable(gmacdev);
122 synopGMAC_enable_dma_tx(gmacdev);
123 return;
124 }
125
126 /**
127 * This sets up the transmit Descriptor queue in ring or chain mode.
128 * This function is tightly coupled to the platform and operating system
129 * Device is interested only after the descriptors are setup. Therefore this function
130 * is not included in the device driver API. This function should be treated as an
131 * example code to design the descriptor structures for ring mode or chain mode.
132 * This function depends on the pcidev structure for allocation consistent dma-able memory in case of linux.
133 * This limitation is due to the fact that linux uses pci structure to allocate a dmable memory
134 * - Allocates the memory for the descriptors.
135 * - Initialize the Busy and Next descriptors indices to 0(Indicating first descriptor).
136 * - Initialize the Busy and Next descriptors to first descriptor address.
137 * - Initialize the last descriptor with the endof ring in case of ring mode.
138 * - Initialize the descriptors in chain mode.
139 * @param[in] pointer to synopGMACdevice.
140 * @param[in] pointer to pci_device structure.
141 * @param[in] number of descriptor expected in tx descriptor queue.
142 * @param[in] whether descriptors to be created in RING mode or CHAIN mode.
143 * \return 0 upon success. Error code upon failure.
144 * \note This function fails if allocation fails for required number of descriptors in Ring mode, but in chain mode
145 * function returns -ESYNOPGMACNOMEM in the process of descriptor chain creation. once returned from this function
146 * user should for gmacdev->TxDescCount to see how many descriptors are there in the chain. Should continue further
147 * only if the number of descriptors in the chain meets the requirements
148 */
149
synopGMAC_setup_tx_desc_queue(synopGMACdevice * gmacdev,u32 no_of_desc,u32 desc_mode)150 s32 synopGMAC_setup_tx_desc_queue(synopGMACdevice * gmacdev,u32 no_of_desc, u32 desc_mode)
151 {
152 s32 i;
153
154 DmaDesc *first_desc = &tx_desc[gmacdev->Intf][0];
155 gmacdev->TxDescCount = 0;
156
157 TR("Total size of memory required for Tx Descriptors in Ring Mode = 0x%08x\n",((sizeof(DmaDesc) * no_of_desc)));
158
159 gmacdev->TxDescCount = no_of_desc;
160 gmacdev->TxDesc = first_desc;
161 #ifdef CACHE_ON
162 gmacdev->TxDescDma = (DmaDesc *)((u64)first_desc | 0x100000000);
163 #else
164 gmacdev->TxDescDma = (DmaDesc *)((u64)first_desc);
165 #endif
166 for(i =0; i < gmacdev -> TxDescCount; i++) {
167 synopGMAC_tx_desc_init_ring(gmacdev->TxDescDma + i, i == gmacdev->TxDescCount-1);
168 TR("%02d %08x \n",i, (unsigned int)(gmacdev->TxDesc + i) );
169 }
170
171
172 gmacdev->TxNext = 0;
173 gmacdev->TxBusy = 0;
174 gmacdev->TxNextDesc = gmacdev->TxDesc;
175 gmacdev->TxBusyDesc = gmacdev->TxDesc;
176 gmacdev->BusyTxDesc = 0;
177
178 return 0;
179 }
180
181
182 /**
183 * This sets up the receive Descriptor queue in ring or chain mode.
184 * This function is tightly coupled to the platform and operating system
185 * Device is interested only after the descriptors are setup. Therefore this function
186 * is not included in the device driver API. This function should be treated as an
187 * example code to design the descriptor structures in ring mode or chain mode.
188 * This function depends on the pcidev structure for allocation of consistent dma-able memory in case of linux.
189 * This limitation is due to the fact that linux uses pci structure to allocate a dmable memory
190 * - Allocates the memory for the descriptors.
191 * - Initialize the Busy and Next descriptors indices to 0(Indicating first descriptor).
192 * - Initialize the Busy and Next descriptors to first descriptor address.
193 * - Initialize the last descriptor with the endof ring in case of ring mode.
194 * - Initialize the descriptors in chain mode.
195 * @param[in] pointer to synopGMACdevice.
196 * @param[in] pointer to pci_device structure.
197 * @param[in] number of descriptor expected in rx descriptor queue.
198 * @param[in] whether descriptors to be created in RING mode or CHAIN mode.
199 * \return 0 upon success. Error code upon failure.
200 * \note This function fails if allocation fails for required number of descriptors in Ring mode, but in chain mode
201 * function returns -ESYNOPGMACNOMEM in the process of descriptor chain creation. once returned from this function
202 * user should for gmacdev->RxDescCount to see how many descriptors are there in the chain. Should continue further
203 * only if the number of descriptors in the chain meets the requirements
204 */
synopGMAC_setup_rx_desc_queue(synopGMACdevice * gmacdev,u32 no_of_desc,u32 desc_mode)205 s32 synopGMAC_setup_rx_desc_queue(synopGMACdevice * gmacdev,u32 no_of_desc, u32 desc_mode)
206 {
207 s32 i;
208 DmaDesc *first_desc = &rx_desc[gmacdev->Intf][0];
209 gmacdev->RxDescCount = 0;
210
211
212 TR("total size of memory required for Rx Descriptors in Ring Mode = 0x%08x\n",((sizeof(DmaDesc) * no_of_desc)));
213
214 gmacdev->RxDescCount = no_of_desc;
215 gmacdev->RxDesc = first_desc;
216 #ifdef CACHE_ON
217 gmacdev->RxDescDma = (DmaDesc *)((u64)first_desc | 0x100000000);
218 #else
219 gmacdev->RxDescDma = (DmaDesc *)((u64)first_desc);
220 #endif
221 for(i =0; i < gmacdev -> RxDescCount; i++) {
222 synopGMAC_rx_desc_init_ring(gmacdev->RxDescDma + i, i == gmacdev->RxDescCount-1);
223 TR("%02d %08x \n",i, (unsigned int)(gmacdev->RxDesc + i));
224 }
225
226
227 gmacdev->RxNext = 0;
228 gmacdev->RxBusy = 0;
229 gmacdev->RxNextDesc = gmacdev->RxDesc;
230 gmacdev->RxBusyDesc = gmacdev->RxDesc;
231
232 gmacdev->BusyRxDesc = 0;
233
234 return 0;
235 }
236
237 /**
238 * This gives up the receive Descriptor queue in ring or chain mode.
239 * This function is tightly coupled to the platform and operating system
240 * Once device's Dma is stopped the memory descriptor memory and the buffer memory deallocation,
241 * is completely handled by the operating system, this call is kept outside the device driver Api.
242 * This function should be treated as an example code to de-allocate the descriptor structures in ring mode or chain mode
243 * and network buffer deallocation.
244 * This function depends on the pcidev structure for dma-able memory deallocation for both descriptor memory and the
245 * network buffer memory under linux.
246 * The responsibility of this function is to
247 * - Free the network buffer memory if any.
248 * - Fee the memory allocated for the descriptors.
249 * @param[in] pointer to synopGMACdevice.
250 * @param[in] pointer to pci_device structure.
251 * @param[in] number of descriptor expected in rx descriptor queue.
252 * @param[in] whether descriptors to be created in RING mode or CHAIN mode.
253 * \return 0 upon success. Error code upon failure.
254 * \note No referece should be made to descriptors once this function is called. This function is invoked when the device is closed.
255 */
synopGMAC_giveup_rx_desc_queue(synopGMACdevice * gmacdev,u32 desc_mode)256 void synopGMAC_giveup_rx_desc_queue(synopGMACdevice * gmacdev, u32 desc_mode)
257 {
258 gmacdev->RxDesc = NULL;
259 gmacdev->RxDescDma = 0;
260 return;
261 }
262
263 /**
264 * This gives up the transmit Descriptor queue in ring or chain mode.
265 * This function is tightly coupled to the platform and operating system
266 * Once device's Dma is stopped the memory descriptor memory and the buffer memory deallocation,
267 * is completely handled by the operating system, this call is kept outside the device driver Api.
268 * This function should be treated as an example code to de-allocate the descriptor structures in ring mode or chain mode
269 * and network buffer deallocation.
270 * This function depends on the pcidev structure for dma-able memory deallocation for both descriptor memory and the
271 * network buffer memory under linux.
272 * The responsibility of this function is to
273 * - Free the network buffer memory if any.
274 * - Fee the memory allocated for the descriptors.
275 * @param[in] pointer to synopGMACdevice.
276 * @param[in] pointer to pci_device structure.
277 * @param[in] number of descriptor expected in tx descriptor queue.
278 * @param[in] whether descriptors to be created in RING mode or CHAIN mode.
279 * \return 0 upon success. Error code upon failure.
280 * \note No reference should be made to descriptors once this function is called. This function is invoked when the device is closed.
281 */
synopGMAC_giveup_tx_desc_queue(synopGMACdevice * gmacdev,u32 desc_mode)282 void synopGMAC_giveup_tx_desc_queue(synopGMACdevice * gmacdev, u32 desc_mode)
283 {
284
285
286 gmacdev->TxDesc = NULL;
287 gmacdev->TxDescDma = 0;
288 return;
289 }
290
291 /**
292 * Function to handle housekeeping after a packet is transmitted over the wire.
293 * After the transmission of a packet DMA generates corresponding interrupt
294 * (if it is enabled). It takes care of returning the sk_buff to the linux
295 * kernel, updating the networking statistics and tracking the descriptors.
296 * @param[in] pointer to net_device structure.
297 * \return void.
298 * \note This function runs in interrupt context
299 */
synop_handle_transmit_over(int intf)300 void synop_handle_transmit_over(int intf)
301 {
302 synopGMACdevice * gmacdev;
303 s32 desc_index;
304 u32 data1;
305 u32 status;
306 u32 length1;
307 u32 dma_addr1;
308
309 u32 ext_status;
310 //u16 time_stamp_higher;
311 u32 time_stamp_high;
312 u32 time_stamp_low;
313
314
315 gmacdev = &GMACdev[intf];
316
317 /*Handle the transmit Descriptors*/
318 do {
319
320 desc_index = synopGMAC_get_tx_qptr(gmacdev, &status, &dma_addr1, &length1, &data1,&ext_status,&time_stamp_high,&time_stamp_low);
321 //synopGMAC_TS_read_timestamp_higher_val(gmacdev, &time_stamp_higher);
322
323 if(desc_index >= 0 /*&& data1 != 0*/) {
324 TR("Finished Transmit at Tx Descriptor %d for skb 0x%08x and buffer = %08x whose status is %08x \n", desc_index,data1,dma_addr1,status);
325
326 if(synopGMAC_is_tx_ipv4header_checksum_error(gmacdev, status)) {
327 TR("Harware Failed to Insert IPV4 Header Checksum\n");
328 gmacdev->synopGMACNetStats.tx_ip_header_errors++;
329 }
330 if(synopGMAC_is_tx_payload_checksum_error(gmacdev, status)) {
331 TR("Harware Failed to Insert Payload Checksum\n");
332 gmacdev->synopGMACNetStats.tx_ip_payload_errors++;
333 }
334
335
336
337 if(synopGMAC_is_desc_valid(status)) {
338 gmacdev->synopGMACNetStats.tx_bytes += length1;
339 gmacdev->synopGMACNetStats.tx_packets++;
340 if(status & DescTxTSStatus) {
341 gmacdev->tx_sec = time_stamp_high;
342 gmacdev->tx_subsec = time_stamp_low;
343 } else {
344 gmacdev->tx_sec = 0;
345 gmacdev->tx_subsec = 0;
346 }
347 } else {
348 TR("Error in Status %08x\n",status);
349 gmacdev->synopGMACNetStats.tx_errors++;
350 gmacdev->synopGMACNetStats.tx_aborted_errors += synopGMAC_is_tx_aborted(status);
351 gmacdev->synopGMACNetStats.tx_carrier_errors += synopGMAC_is_tx_carrier_error(status);
352 }
353 }
354 gmacdev->synopGMACNetStats.collisions += synopGMAC_get_tx_collision_count(status);
355 } while(desc_index >= 0);
356
357 }
358
359
360
361
362 /**
363 * Function to Receive a packet from the interface.
364 * After Receiving a packet, DMA transfers the received packet to the system memory
365 * and generates corresponding interrupt (if it is enabled). This function prepares
366 * the sk_buff for received packet after removing the ethernet CRC, and hands it over
367 * to linux networking stack.
368 * - Updataes the networking interface statistics
369 * - Keeps track of the rx descriptors
370 * @param[in] pointer to net_device structure.
371 * \return void.
372 * \note This function runs in interrupt context.
373 */
374 extern DmaDesc * prevtx; // for CRC test
synop_handle_received_data(int intf,u8 ** buf)375 s32 synop_handle_received_data(int intf, u8 **buf) // Chris, to get RX buffer pointer
376 {
377
378 synopGMACdevice * gmacdev;
379 s32 desc_index;
380
381 u32 data1;
382 u32 len = 0;
383 u32 status;
384 u32 dma_addr1;
385
386 u32 ext_status;
387 //u16 time_stamp_higher;
388 u32 time_stamp_high;
389 u32 time_stamp_low;
390 struct sk_buff *rb = &rxbuf[intf];
391
392 //struct sk_buff *skb; //This is the pointer to hold the received data
393
394 TR("%s\n",__FUNCTION__);
395
396
397
398 gmacdev = &GMACdev[intf];
399
400 /*Handle the Receive Descriptors*/
401 do {
402
403 desc_index = synopGMAC_get_rx_qptr(gmacdev, &status,
404 &dma_addr1, NULL, &data1,
405 &ext_status, &time_stamp_high, &time_stamp_low);
406 if(desc_index >0) {
407 //synopGMAC_TS_read_timestamp_higher_val(gmacdev, &time_stamp_higher);
408 //TR("S:%08x ES:%08x DA1:%08x d1:%08x TSH:%08x TSL:%08x TSHW:%08x \n",status,ext_status,dma_addr1, data1,time_stamp_high,time_stamp_low,time_stamp_higher);
409 TR("S:%08x ES:%08x DA1:%08x d1:%08x TSH:%08x TSL:%08x\n",status,ext_status,dma_addr1, data1,time_stamp_high,time_stamp_low);
410 }
411
412 if(desc_index >= 0 /*&& data1 != 0*/) {
413 TR("Received Data at Rx Descriptor %d for skb 0x%08x whose status is %08x\n",desc_index,data1,status);
414
415
416 //skb = (struct sk_buff *)((u64)data1);
417 if(1/*synopGMAC_is_rx_desc_valid(status)*/) {
418 // Always enter this loop. synopGMAC_is_rx_desc_valid() also report invalid descriptor
419 // if there's packet error generated by test code and drop it. But we need to execute ext_status
420 // check code to tell what's going on. --ya
421
422 len = synopGMAC_get_rx_desc_frame_length(status) - 4; //Not interested in Ethernet CRC bytes
423
424
425 // Now lets check for the IPC offloading
426 /* Since we have enabled the checksum offloading in hardware, lets inform the kernel
427 not to perform the checksum computation on the incoming packet. Note that ip header
428 checksum will be computed by the kernel immaterial of what we inform. Similary TCP/UDP/ICMP
429 pseudo header checksum will be computed by the stack. What we can inform is not to perform
430 payload checksum.
431 When CHECKSUM_UNNECESSARY is set kernel bypasses the checksum computation.
432 */
433
434 TR("Checksum Offloading will be done now\n");
435
436 if(synopGMAC_is_ext_status(gmacdev, status)) { // extended status present indicates that the RDES4 need to be probed
437 TR("Extended Status present\n");
438 if(synopGMAC_ES_is_IP_header_error(gmacdev,ext_status)) { // IP header (IPV4) checksum error
439 //Linux Kernel doesnot care for ipv4 header checksum. So we will simply proceed by printing a warning ....
440 TR("(EXTSTS)Error in IP header error\n");
441 gmacdev->synopGMACNetStats.rx_ip_header_errors++;
442 }
443 if(synopGMAC_ES_is_rx_checksum_bypassed(gmacdev,ext_status)) { // Hardware engine bypassed the checksum computation/checking
444 TR("(EXTSTS)Hardware bypassed checksum computation\n");
445 }
446 if(synopGMAC_ES_is_IP_payload_error(gmacdev,ext_status)) { // IP payload checksum is in error (UDP/TCP/ICMP checksum error)
447 TR("(EXTSTS) Error in EP payload\n");
448 gmacdev->synopGMACNetStats.rx_ip_payload_errors++;
449 }
450 } else { // No extended status. So relevant information is available in the status itself
451 if(synopGMAC_is_rx_checksum_error(gmacdev, status) == RxNoChkError ) {
452 TR("Ip header and TCP/UDP payload checksum Bypassed <Chk Status = 4> \n");
453 }
454 if(synopGMAC_is_rx_checksum_error(gmacdev, status) == RxIpHdrChkError ) {
455 //Linux Kernel doesnot care for ipv4 header checksum. So we will simply proceed by printing a warning ....
456 TR(" Error in 16bit IPV4 Header Checksum <Chk Status = 6> \n");
457 gmacdev->synopGMACNetStats.rx_ip_header_errors++;
458 }
459 if(synopGMAC_is_rx_checksum_error(gmacdev, status) == RxLenLT600 ) {
460 TR("IEEE 802.3 type frame with Length field Lesss than 0x0600 <Chk Status = 0> \n");
461 }
462 if(synopGMAC_is_rx_checksum_error(gmacdev, status) == RxIpHdrPayLoadChkBypass ) {
463 TR("Ip header and TCP/UDP payload checksum Bypassed <Chk Status = 1>\n");
464 }
465 if(synopGMAC_is_rx_checksum_error(gmacdev, status) == RxChkBypass ) {
466 TR("Ip header and TCP/UDP payload checksum Bypassed <Chk Status = 3> \n");
467 }
468 if(synopGMAC_is_rx_checksum_error(gmacdev, status) == RxPayLoadChkError ) {
469 TR(" TCP/UDP payload checksum Error <Chk Status = 5> \n");
470 gmacdev->synopGMACNetStats.rx_ip_payload_errors++;
471 }
472 if(synopGMAC_is_rx_checksum_error(gmacdev, status) == RxIpHdrPayLoadChkError ) {
473 //Linux Kernel doesnot care for ipv4 header checksum. So we will simply proceed by printing a warning ....
474 TR(" Both IP header and Payload Checksum Error <Chk Status = 7> \n");
475 gmacdev->synopGMACNetStats.rx_ip_header_errors++;
476 gmacdev->synopGMACNetStats.rx_ip_payload_errors++;
477 }
478 }
479 #if 0
480 #ifdef CACHE_ON
481 memcpy((void *)rb->data, (void *)((u64)dma_addr1 | 0x100000000), len);
482 #else
483 memcpy((void *)rb->data, (void *)((u64)dma_addr1), len);
484 #endif
485 if(prevtx != NULL) {
486 #ifdef CACHE_ON
487 memcpy((void *)(rb->data + len), (void *)((u64)(dma_addr1 | 0x100000000) + len), 4);
488 #else
489 memcpy((void *)(rb->data + len), (void *)((u64)dma_addr1 + len), 4);
490 #endif
491 }
492 #else
493 *buf = (u8 *)(u32)((u64)dma_addr1);
494 #endif
495 rb->rdy = 1;
496 rb->len = len;
497 gmacdev->synopGMACNetStats.rx_packets++;
498 gmacdev->synopGMACNetStats.rx_bytes += len;
499 if(status & DescRxTSAvailable) {
500 gmacdev->rx_sec = time_stamp_high;
501 gmacdev->rx_subsec = time_stamp_low;
502 } else {
503 gmacdev->rx_sec = 0;
504 gmacdev->rx_subsec = 0;
505 }
506 } else {
507 /*Now the present skb should be set free*/
508 TR("s: %08x\n",status);
509 gmacdev->synopGMACNetStats.rx_errors++;
510 gmacdev->synopGMACNetStats.collisions += synopGMAC_is_rx_frame_collision(status);
511 gmacdev->synopGMACNetStats.rx_crc_errors += synopGMAC_is_rx_crc(status);
512 gmacdev->synopGMACNetStats.rx_frame_errors += synopGMAC_is_frame_dribbling_errors(status);
513 gmacdev->synopGMACNetStats.rx_length_errors += synopGMAC_is_rx_frame_length_errors(status);
514 }
515 }
516 } while(0); //while(desc_index >= 0);
517 return len;
518 }
519
520 u32 volatile LPIStsChange = 0;
521 u32 volatile LPIReg = 0;
522 /**
523 * Interrupt service routing.
524 * This is the function registered as ISR for device interrupts.
525 * @param[in] interrupt number.
526 * @param[in] void pointer to device unique structure (Required for shared interrupts in Linux).
527 * @param[in] pointer to pt_regs (not used).
528 * \return Returns IRQ_NONE if not device interrupts IRQ_HANDLED for device interrupts.
529 * \note This function runs in interrupt context
530 *
531 */
synopGMAC0_intr_handler(void)532 void synopGMAC0_intr_handler(void)
533 {
534 synopGMACdevice * gmacdev = &GMACdev[0];
535 u32 interrupt,dma_status_reg, mac_status_reg;
536 s32 status;
537
538 // Check GMAC interrupt
539 mac_status_reg = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacInterruptStatus);
540 if(mac_status_reg & GmacTSIntSts) {
541 gmacdev->synopGMACNetStats.ts_int = 1;
542 status = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacTSStatus);
543 if(!(status & (1 << 1)))
544 printf("TS alarm flag not set??\n");
545 else
546 printf("TS alarm!!!!!!!!!!!!!!!!\n");
547
548 }
549 if(mac_status_reg & GmacLPIIntSts) {
550 //printf("LPI\n");
551 LPIStsChange = 1;
552 LPIReg = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacLPICtrlSts);
553
554 }
555 if(mac_status_reg & GmacRgmiiIntSts) {
556 u32 volatile reg;
557 reg = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacRgmiiCtrlSts);
558
559 }
560 synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacInterruptStatus ,mac_status_reg);
561
562 /*Read the Dma interrupt status to know whether the interrupt got generated by our device or not*/
563 dma_status_reg = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaStatus);
564 //printf("i");
565 //printf("i %08x %08x\n", mac_status_reg, dma_status_reg);
566
567 if(dma_status_reg == 0)
568 return;
569
570 synopGMAC_disable_interrupt_all(gmacdev);
571
572 TR("%s:Dma Status Reg: 0x%08x\n",__FUNCTION__,dma_status_reg);
573
574 if(dma_status_reg & GmacPmtIntr) {
575 TR("%s:: Interrupt due to PMT module\n",__FUNCTION__);
576 synopGMAC_powerup_mac(gmacdev);
577 }
578
579 if(dma_status_reg & GmacLineIntfIntr) {
580 TR("%s:: Interrupt due to GMAC LINE module\n",__FUNCTION__);
581 }
582
583 /*Now lets handle the DMA interrupts*/
584 interrupt = synopGMAC_get_interrupt_type(gmacdev);
585 TR("%s:Interrupts to be handled: 0x%08x\n",__FUNCTION__,interrupt);
586
587
588 if(interrupt & synopGMACDmaError) {
589
590 TR("%s::Fatal Bus Error Inetrrupt Seen\n",__FUNCTION__);
591 synopGMAC_disable_dma_tx(gmacdev);
592 synopGMAC_disable_dma_rx(gmacdev);
593
594 synopGMAC_take_desc_ownership_tx(gmacdev);
595 synopGMAC_take_desc_ownership_rx(gmacdev);
596
597 synopGMAC_init_tx_rx_desc_queue(gmacdev);
598
599 synopGMAC_reset(gmacdev);//reset the DMA engine and the GMAC ip
600
601 synopGMAC_set_mac_addr(gmacdev,GmacAddr0High,GmacAddr0Low, gmacdev->Intf == 0 ? mac_addr0 : mac_addr1);
602 synopGMAC_dma_bus_mode_init(gmacdev,DmaFixedBurstEnable| DmaBurstLength8 | DmaDescriptorSkip0/*DmaDescriptorSkip2*/ );
603 synopGMAC_dma_control_init(gmacdev,DmaStoreAndForward);
604 synopGMAC_init_rx_desc_base(gmacdev);
605 synopGMAC_init_tx_desc_base(gmacdev);
606 synopGMAC_mac_init(gmacdev);
607 synopGMAC_enable_dma_rx(gmacdev);
608 synopGMAC_enable_dma_tx(gmacdev);
609
610 }
611
612
613 if(interrupt & synopGMACDmaRxNormal) {
614 u8 **buf = NULL;
615 //printf("rx\n");
616 TR("%s:: Rx Normal \n", __FUNCTION__);
617 synop_handle_received_data(0, buf); // Chris, to get RX buffer pointer
618 }
619
620 if(interrupt & synopGMACDmaRxAbnormal) {
621 TR("%s::Abnormal Rx Interrupt Seen\n",__FUNCTION__);
622 gmacdev->synopGMACNetStats.rx_over_errors++;
623 #if 1
624
625 if(gmacdev->GMAC_Power_down == 0) { // If Mac is not in powerdown
626 synopGMAC_resume_dma_rx(gmacdev);//To handle GBPS with 12 descriptors
627 }
628 #endif
629 }
630
631 if(interrupt & synopGMACDmaRxStopped) {
632 TR("%s::Receiver stopped seeing Rx interrupts\n",__FUNCTION__); //Receiver gone in to stopped state
633 #if 1
634 if(gmacdev->GMAC_Power_down == 0) { // If Mac is not in powerdown
635 gmacdev->synopGMACNetStats.rx_over_errors++;
636 synopGMAC_enable_dma_rx(gmacdev);
637 }
638 #endif
639 }
640
641 if(interrupt & synopGMACDmaTxNormal) {
642 //printf("tx\n");
643 //xmit function has done its job
644 TR("%s::Finished Normal Transmission \n",__FUNCTION__);
645 synop_handle_transmit_over(0);//Do whatever you want after the transmission is over
646
647
648 }
649
650 if(interrupt & synopGMACDmaTxAbnormal) {
651 TR("%s::Abnormal Tx Interrupt Seen\n",__FUNCTION__);
652 #if 1
653 if(gmacdev->GMAC_Power_down == 0) { // If Mac is not in powerdown
654 synop_handle_transmit_over(0);
655 }
656 #endif
657 }
658
659
660
661 if(interrupt & synopGMACDmaTxStopped) {
662 TR("%s::Transmitter stopped sending the packets\n",__FUNCTION__);
663 #if 1
664 if(gmacdev->GMAC_Power_down == 0) { // If Mac is not in powerdown
665 synopGMAC_disable_dma_tx(gmacdev);
666 synopGMAC_take_desc_ownership_tx(gmacdev);
667
668 synopGMAC_enable_dma_tx(gmacdev);
669 TR("%s::Transmission Resumed\n",__FUNCTION__);
670 }
671 #endif
672 }
673
674 /* Enable the interrupt before returning from ISR*/
675 synopGMAC_enable_interrupt(gmacdev,DmaIntEnable);
676 return;
677 }
678
synopGMAC_set_speed(int intf)679 void synopGMAC_set_speed(int intf)
680 {
681
682 synopGMACdevice *gmacdev = &GMACdev[intf];
683
684 switch (gmacdev->Speed) {
685 case SPEED1000:
686 synopGMACClearBits((u32 *)gmacdev->MacBase,GmacConfig,GmacMiiGmii);
687 break;
688 case SPEED100:
689 synopGMACSetBits((u32 *)gmacdev->MacBase,GmacConfig,GmacMiiGmii);
690 synopGMACSetBits((u32 *)gmacdev->MacBase,GmacConfig,GmacFESpeed100);
691 break;
692 case SPEED10:
693 synopGMACSetBits((u32 *)gmacdev->MacBase,GmacConfig,GmacMiiGmii);
694 synopGMACClearBits((u32 *)gmacdev->MacBase,GmacConfig,GmacFESpeed100);
695 default:
696 break;
697 }
698
699 }
700
701 /**
702 * Function used when the interface is opened for use.
703 * We register synopGMAC_linux_open function to linux open(). Basically this
704 * function prepares the the device for operation . This function is called whenever ifconfig (in Linux)
705 * activates the device (for example "ifconfig eth0 up"). This function registers
706 * system resources needed
707 * - Attaches device to device specific structure
708 * - Programs the MDC clock for PHY configuration
709 * - Check and initialize the PHY interface
710 * - ISR registration
711 * - Setup and initialize Tx and Rx descriptors
712 * - Initialize MAC and DMA
713 * - Allocate Memory for RX descriptors (The should be DMAable)
714 * - Initialize one second timer to detect cable plug/unplug
715 * - Configure and Enable Interrupts
716 * - Enable Tx and Rx
717 * - start the Linux network queue interface
718 * @param[in] pointer to net_device structure.
719 * \return Returns 0 on success and error status upon failure.
720 * \callgraph
721 */
722
synopGMAC_open(int intf)723 s32 synopGMAC_open(int intf)
724 {
725 //s32 status = 0;
726 s32 i;
727 //s32 reserve_len=2;
728 struct sk_buff *skb;
729 synopGMACdevice * gmacdev = &GMACdev[intf];
730
731 /*Attach the device to MAC struct This will configure all the required base addresses
732 such as Mac base, configuration base, phy base address(out of 32 possible phys )*/
733 if(intf == 0)
734 synopGMAC_attach(gmacdev, GMAC0MappedAddr + MACBASE, GMAC0MappedAddr + DMABASE, DEFAULT_PHY_BASE);
735 else
736 synopGMAC_attach(gmacdev, GMAC1MappedAddr + MACBASE, GMAC1MappedAddr + DMABASE, DEFAULT_PHY_BASE);
737
738 synopGMAC_reset(gmacdev); // Reset to make RGMII/RMII setting take affect --ya
739 gmacdev->Intf = intf;
740 /*Lets read the version of ip in to device structure*/
741 synopGMAC_read_version(gmacdev);
742
743 /*Check for Phy initialization*/
744 synopGMAC_set_mdc_clk_div(gmacdev,GmiiCsrClk5);
745 //synopGMAC_set_mdc_clk_div(gmacdev, (GmiiCsrClk2|BIT5));
746 gmacdev->ClockDivMdc = synopGMAC_get_mdc_clk_div(gmacdev);
747 //status = synopGMAC_check_phy_init(gmacdev);
748 synopGMAC_check_phy_init(gmacdev);
749
750 /*Set up the tx and rx descriptor queue/ring*/
751
752 synopGMAC_setup_tx_desc_queue(gmacdev,TRANSMIT_DESC_SIZE, RINGMODE);
753 synopGMAC_init_tx_desc_base(gmacdev); //Program the transmit descriptor base address in to DmaTxBase addr
754
755 synopGMAC_setup_rx_desc_queue(gmacdev,RECEIVE_DESC_SIZE, RINGMODE);
756 synopGMAC_init_rx_desc_base(gmacdev); //Program the transmit descriptor base address in to DmaTxBase addr
757
758
759 synopGMAC_dma_bus_mode_init(gmacdev, DmaBurstLength32 | DmaDescriptorSkip0/*DmaDescriptorSkip2*/ | DmaDescriptor8Words ); //pbl32 incr with rxthreshold 128 and Desc is 8 Words
760
761 synopGMAC_dma_control_init(gmacdev,DmaStoreAndForward |DmaTxSecondFrame|DmaRxThreshCtrl128);
762
763 /*Initialize the mac interface*/
764
765 synopGMAC_mac_init(gmacdev);
766 synopGMAC_promisc_enable(gmacdev);
767
768 synopGMAC_pause_control(gmacdev); // This enables the pause control in Full duplex mode of operation
769
770 #if 0
771 /*IPC Checksum offloading is enabled for this driver. Should only be used if Full Ip checksumm offload engine is configured in the hardware*/
772 synopGMAC_enable_rx_chksum_offload(gmacdev); //Enable the offload engine in the receive path
773 synopGMAC_rx_tcpip_chksum_drop_enable(gmacdev); // This is default configuration, DMA drops the packets if error in encapsulated ethernet payload
774 #endif
775
776 for(i = 0; i < RECEIVE_DESC_SIZE; i ++) {
777 skb = &rx_buf[intf][i];
778 synopGMAC_set_rx_qptr(gmacdev, (u32)((u64)(skb->data) & 0xFFFFFFFF), sizeof(skb->data), (u32)((u64)skb & 0xFFFFFFFF));
779 }
780
781 synopGMAC_clear_interrupt(gmacdev);
782
783 synopGMAC_enable_interrupt(gmacdev,DmaIntEnable);
784 synopGMAC_enable_dma_rx(gmacdev);
785 synopGMAC_enable_dma_tx(gmacdev);
786
787
788 synopGMAC_set_mac_address(intf, intf == 0 ? mac_addr0 : mac_addr1);
789
790
791 return 0;
792
793 }
794
795 /**
796 * Function used when the interface is closed.
797 *
798 * This function is registered to linux stop() function. This function is
799 * called whenever ifconfig (in Linux) closes the device (for example "ifconfig eth0 down").
800 * This releases all the system resources allocated during open call.
801 * system resources int needs
802 * - Disable the device interrupts
803 * - Stop the receiver and get back all the rx descriptors from the DMA
804 * - Stop the transmitter and get back all the tx descriptors from the DMA
805 * - Stop the Linux network queue interface
806 * - Free the irq (ISR registered is removed from the kernel)
807 * - Release the TX and RX descripor memory
808 * - De-initialize one second timer rgistered for cable plug/unplug tracking
809 * @param[in] pointer to net_device structure.
810 * \return Returns 0 on success and error status upon failure.
811 * \callgraph
812 */
813
synopGMAC_close(int intf)814 s32 synopGMAC_close(int intf)
815 {
816
817 synopGMACdevice * gmacdev = &GMACdev[intf];;
818
819 //TR0("%s\n",__FUNCTION__);
820
821 /*Disable all the interrupts*/
822 synopGMAC_disable_interrupt_all(gmacdev);
823
824
825 TR("the synopGMAC interrupt has been disabled\n");
826
827 /*Disable the reception*/
828 synopGMAC_disable_dma_rx(gmacdev);
829 synopGMAC_take_desc_ownership_rx(gmacdev);
830 TR("the synopGMAC Reception has been disabled\n");
831
832 /*Disable the transmission*/
833 synopGMAC_disable_dma_tx(gmacdev);
834 synopGMAC_take_desc_ownership_tx(gmacdev);
835
836 TR("the synopGMAC interrupt handler has been removed\n");
837
838 /*Free the Rx Descriptor contents*/
839 TR("Now calling synopGMAC_giveup_rx_desc_queue \n");
840 synopGMAC_giveup_rx_desc_queue(gmacdev, RINGMODE);
841
842 TR("Now calling synopGMAC_giveup_tx_desc_queue \n");
843 synopGMAC_giveup_tx_desc_queue(gmacdev, RINGMODE);
844
845 return 0;
846
847 }
848
849
850 /**
851 * Function to transmit a given packet on the wire.
852 * Whenever Linux Kernel has a packet ready to be transmitted, this function is called.
853 * The function prepares a packet and prepares the descriptor and
854 * enables/resumes the transmission.
855 * @param[in] pointer to sk_buff structure.
856 * @param[in] pointer to net_device structure.
857 * \return Returns 0 on success and Error code on failure.
858 * \note structure sk_buff is used to hold packet in Linux networking stacks.
859 */
synopGMAC_xmit_frames(struct sk_buff * skb,int intf,u32 offload_needed,u32 ts)860 s32 synopGMAC_xmit_frames(struct sk_buff *skb, int intf, u32 offload_needed, u32 ts)
861 {
862 s32 status = 0;
863
864 u32 dma_addr = (u32)((u64)skb->data & 0xFFFFFFFF);
865
866 synopGMACdevice * gmacdev;
867
868
869 gmacdev = &GMACdev[intf];
870
871 /*Now we have skb ready and OS invoked this function. Lets make our DMA know about this*/
872 status = synopGMAC_set_tx_qptr(gmacdev, dma_addr, skb->len, (u32)((u64)skb & 0xFFFFFFFF), offload_needed, ts);
873 if(status < 0) {
874 TR0("%s No More Free Tx Descriptors\n",__FUNCTION__);
875 return -1;
876 }
877
878 /*Now force the DMA to start transmission*/
879 synopGMAC_resume_dma_tx(gmacdev);
880
881
882 return 0;
883 }
884
885
886 /**
887 * Function to set ethernet address of the NIC.
888 * @param[in] pointer to net_device structure.
889 * @param[in] pointer to an address structure.
890 * \return Returns 0 on success Errorcode on failure.
891 */
synopGMAC_set_mac_address(int intf,u8 * macaddr)892 s32 synopGMAC_set_mac_address(int intf, u8* macaddr)
893 {
894
895
896 synopGMACdevice * gmacdev = NULL;
897
898 gmacdev = &GMACdev[intf];
899
900
901 synopGMAC_set_mac_addr(gmacdev, GmacAddr0High, GmacAddr0Low, macaddr);
902
903 return 0;
904 }
905
906 // mode 0: 1000Mbps, 1: 100Mbps, 2: 10Mbps
907
synopGMAC_set_mode(int intf,int mode)908 void synopGMAC_set_mode(int intf, int mode)
909 {
910
911 synopGMACdevice *gmacdev = &GMACdev[intf];
912
913 // Must stop Tx/Rx before change speed/mode
914 synopGMAC_tx_disable(gmacdev);
915 synopGMAC_rx_disable(gmacdev);
916 switch (mode) {
917 case 0:
918 synopGMACClearBits((u32 *)gmacdev->MacBase,GmacConfig,GmacMiiGmii);
919 gmacdev->Speed = SPEED1000;
920 break;
921 case 1:
922 synopGMACSetBits((u32 *)gmacdev->MacBase,GmacConfig,GmacMiiGmii);
923 synopGMACSetBits((u32 *)gmacdev->MacBase,GmacConfig,GmacFESpeed100);
924 gmacdev->Speed = SPEED100;
925 break;
926 case 2:
927 synopGMACSetBits((u32 *)gmacdev->MacBase,GmacConfig,GmacMiiGmii);
928 synopGMACClearBits((u32 *)gmacdev->MacBase,GmacConfig,GmacFESpeed100);
929 gmacdev->Speed = SPEED10;
930 default:
931 break;
932 }
933 synopGMAC_tx_enable(gmacdev);
934 synopGMAC_rx_enable(gmacdev);
935 }
936
937