]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/net/stmmac/dwmac100.c
stmmac: rename mac100 as dwmac100 and fix spare coding style
[net-next-2.6.git] / drivers / net / stmmac / dwmac100.c
CommitLineData
47dd7a54
GC
1/*******************************************************************************
2 This is the driver for the MAC 10/100 on-chip Ethernet controller
3 currently tested on all the ST boards based on STb7109 and stx7200 SoCs.
4
5 DWC Ether MAC 10/100 Universal version 4.0 has been used for developing
6 this code.
7
8 Copyright (C) 2007-2009 STMicroelectronics Ltd
9
10 This program is free software; you can redistribute it and/or modify it
11 under the terms and conditions of the GNU General Public License,
12 version 2, as published by the Free Software Foundation.
13
14 This program is distributed in the hope it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 more details.
18
19 You should have received a copy of the GNU General Public License along with
20 this program; if not, write to the Free Software Foundation, Inc.,
21 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
22
23 The full GNU General Public License is included in this distribution in
24 the file called "COPYING".
25
26 Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
27*******************************************************************************/
28
29#include <linux/netdevice.h>
30#include <linux/crc32.h>
31#include <linux/mii.h>
32#include <linux/phy.h>
33
34#include "common.h"
7e848ae1 35#include "dwmac100.h"
aec7ff27 36#include "dwmac_dma.h"
47dd7a54 37
7e848ae1
GC
38#undef DWMAC100_DEBUG
39/*#define DWMAC100_DEBUG*/
40#ifdef DWMAC100_DEBUG
47dd7a54
GC
41#define DBG(fmt, args...) printk(fmt, ## args)
42#else
43#define DBG(fmt, args...) do { } while (0)
44#endif
45
7e848ae1 46static void dwmac100_core_init(unsigned long ioaddr)
47dd7a54
GC
47{
48 u32 value = readl(ioaddr + MAC_CONTROL);
49
50 writel((value | MAC_CORE_INIT), ioaddr + MAC_CONTROL);
51
52#ifdef STMMAC_VLAN_TAG_USED
53 writel(ETH_P_8021Q, ioaddr + MAC_VLAN1);
54#endif
55 return;
56}
57
7e848ae1 58static void dwmac100_dump_mac_regs(unsigned long ioaddr)
47dd7a54
GC
59{
60 pr_info("\t----------------------------------------------\n"
7e848ae1
GC
61 "\t DWMAC 100 CSR (base addr = 0x%8x)\n"
62 "\t----------------------------------------------\n",
63 (unsigned int)ioaddr);
47dd7a54 64 pr_info("\tcontrol reg (offset 0x%x): 0x%08x\n", MAC_CONTROL,
7e848ae1 65 readl(ioaddr + MAC_CONTROL));
47dd7a54 66 pr_info("\taddr HI (offset 0x%x): 0x%08x\n ", MAC_ADDR_HIGH,
7e848ae1 67 readl(ioaddr + MAC_ADDR_HIGH));
47dd7a54 68 pr_info("\taddr LO (offset 0x%x): 0x%08x\n", MAC_ADDR_LOW,
7e848ae1 69 readl(ioaddr + MAC_ADDR_LOW));
47dd7a54 70 pr_info("\tmulticast hash HI (offset 0x%x): 0x%08x\n",
7e848ae1 71 MAC_HASH_HIGH, readl(ioaddr + MAC_HASH_HIGH));
47dd7a54 72 pr_info("\tmulticast hash LO (offset 0x%x): 0x%08x\n",
7e848ae1 73 MAC_HASH_LOW, readl(ioaddr + MAC_HASH_LOW));
47dd7a54
GC
74 pr_info("\tflow control (offset 0x%x): 0x%08x\n",
75 MAC_FLOW_CTRL, readl(ioaddr + MAC_FLOW_CTRL));
76 pr_info("\tVLAN1 tag (offset 0x%x): 0x%08x\n", MAC_VLAN1,
7e848ae1 77 readl(ioaddr + MAC_VLAN1));
47dd7a54 78 pr_info("\tVLAN2 tag (offset 0x%x): 0x%08x\n", MAC_VLAN2,
7e848ae1 79 readl(ioaddr + MAC_VLAN2));
47dd7a54
GC
80 pr_info("\n\tMAC management counter registers\n");
81 pr_info("\t MMC crtl (offset 0x%x): 0x%08x\n",
7e848ae1 82 MMC_CONTROL, readl(ioaddr + MMC_CONTROL));
47dd7a54 83 pr_info("\t MMC High Interrupt (offset 0x%x): 0x%08x\n",
7e848ae1 84 MMC_HIGH_INTR, readl(ioaddr + MMC_HIGH_INTR));
47dd7a54 85 pr_info("\t MMC Low Interrupt (offset 0x%x): 0x%08x\n",
7e848ae1 86 MMC_LOW_INTR, readl(ioaddr + MMC_LOW_INTR));
47dd7a54 87 pr_info("\t MMC High Interrupt Mask (offset 0x%x): 0x%08x\n",
7e848ae1 88 MMC_HIGH_INTR_MASK, readl(ioaddr + MMC_HIGH_INTR_MASK));
47dd7a54 89 pr_info("\t MMC Low Interrupt Mask (offset 0x%x): 0x%08x\n",
7e848ae1 90 MMC_LOW_INTR_MASK, readl(ioaddr + MMC_LOW_INTR_MASK));
47dd7a54
GC
91 return;
92}
93
7e848ae1 94static int dwmac100_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx,
47dd7a54
GC
95 u32 dma_rx)
96{
97 u32 value = readl(ioaddr + DMA_BUS_MODE);
98 /* DMA SW reset */
99 value |= DMA_BUS_MODE_SFT_RESET;
100 writel(value, ioaddr + DMA_BUS_MODE);
101 do {} while ((readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET));
102
103 /* Enable Application Access by writing to DMA CSR0 */
104 writel(DMA_BUS_MODE_DEFAULT | (pbl << DMA_BUS_MODE_PBL_SHIFT),
105 ioaddr + DMA_BUS_MODE);
106
107 /* Mask interrupts by writing to CSR7 */
108 writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
109
110 /* The base address of the RX/TX descriptor lists must be written into
111 * DMA CSR3 and CSR4, respectively. */
112 writel(dma_tx, ioaddr + DMA_TX_BASE_ADDR);
113 writel(dma_rx, ioaddr + DMA_RCV_BASE_ADDR);
114
115 return 0;
116}
117
118/* Store and Forward capability is not used at all..
119 * The transmit threshold can be programmed by
120 * setting the TTC bits in the DMA control register.*/
7e848ae1 121static void dwmac100_dma_operation_mode(unsigned long ioaddr, int txmode,
47dd7a54
GC
122 int rxmode)
123{
124 u32 csr6 = readl(ioaddr + DMA_CONTROL);
125
126 if (txmode <= 32)
127 csr6 |= DMA_CONTROL_TTC_32;
128 else if (txmode <= 64)
129 csr6 |= DMA_CONTROL_TTC_64;
130 else
131 csr6 |= DMA_CONTROL_TTC_128;
132
133 writel(csr6, ioaddr + DMA_CONTROL);
134
135 return;
136}
137
7e848ae1 138static void dwmac100_dump_dma_regs(unsigned long ioaddr)
47dd7a54
GC
139{
140 int i;
141
7e848ae1 142 DBG(KERN_DEBUG "DWMAC 100 DMA CSR \n");
47dd7a54
GC
143 for (i = 0; i < 9; i++)
144 pr_debug("\t CSR%d (offset 0x%x): 0x%08x\n", i,
145 (DMA_BUS_MODE + i * 4),
146 readl(ioaddr + DMA_BUS_MODE + i * 4));
147 DBG(KERN_DEBUG "\t CSR20 (offset 0x%x): 0x%08x\n",
148 DMA_CUR_TX_BUF_ADDR, readl(ioaddr + DMA_CUR_TX_BUF_ADDR));
149 DBG(KERN_DEBUG "\t CSR21 (offset 0x%x): 0x%08x\n",
150 DMA_CUR_RX_BUF_ADDR, readl(ioaddr + DMA_CUR_RX_BUF_ADDR));
151 return;
152}
153
154/* DMA controller has two counters to track the number of
7e848ae1
GC
155 * the receive missed frames. */
156static void dwmac100_dma_diagnostic_fr(void *data,
157 struct stmmac_extra_stats *x,
47dd7a54
GC
158 unsigned long ioaddr)
159{
160 struct net_device_stats *stats = (struct net_device_stats *)data;
161 u32 csr8 = readl(ioaddr + DMA_MISSED_FRAME_CTR);
162
163 if (unlikely(csr8)) {
164 if (csr8 & DMA_MISSED_FRAME_OVE) {
165 stats->rx_over_errors += 0x800;
166 x->rx_overflow_cntr += 0x800;
167 } else {
168 unsigned int ove_cntr;
169 ove_cntr = ((csr8 & DMA_MISSED_FRAME_OVE_CNTR) >> 17);
170 stats->rx_over_errors += ove_cntr;
171 x->rx_overflow_cntr += ove_cntr;
172 }
173
174 if (csr8 & DMA_MISSED_FRAME_OVE_M) {
175 stats->rx_missed_errors += 0xffff;
176 x->rx_missed_cntr += 0xffff;
177 } else {
178 unsigned int miss_f = (csr8 & DMA_MISSED_FRAME_M_CNTR);
179 stats->rx_missed_errors += miss_f;
180 x->rx_missed_cntr += miss_f;
181 }
182 }
183 return;
184}
185
7e848ae1
GC
186static int dwmac100_get_tx_frame_status(void *data,
187 struct stmmac_extra_stats *x,
47dd7a54
GC
188 struct dma_desc *p, unsigned long ioaddr)
189{
190 int ret = 0;
191 struct net_device_stats *stats = (struct net_device_stats *)data;
192
193 if (unlikely(p->des01.tx.error_summary)) {
194 if (unlikely(p->des01.tx.underflow_error)) {
195 x->tx_underflow++;
196 stats->tx_fifo_errors++;
197 }
198 if (unlikely(p->des01.tx.no_carrier)) {
199 x->tx_carrier++;
200 stats->tx_carrier_errors++;
201 }
202 if (unlikely(p->des01.tx.loss_carrier)) {
203 x->tx_losscarrier++;
204 stats->tx_carrier_errors++;
205 }
206 if (unlikely((p->des01.tx.excessive_deferral) ||
207 (p->des01.tx.excessive_collisions) ||
208 (p->des01.tx.late_collision)))
209 stats->collisions += p->des01.tx.collision_count;
210 ret = -1;
211 }
212 if (unlikely(p->des01.tx.heartbeat_fail)) {
213 x->tx_heartbeat++;
214 stats->tx_heartbeat_errors++;
215 ret = -1;
216 }
217 if (unlikely(p->des01.tx.deferred))
218 x->tx_deferred++;
219
220 return ret;
221}
222
7e848ae1 223static int dwmac100_get_tx_len(struct dma_desc *p)
47dd7a54
GC
224{
225 return p->des01.tx.buffer1_size;
226}
227
228/* This function verifies if each incoming frame has some errors
229 * and, if required, updates the multicast statistics.
230 * In case of success, it returns csum_none becasue the device
231 * is not able to compute the csum in HW. */
7e848ae1
GC
232static int dwmac100_get_rx_frame_status(void *data,
233 struct stmmac_extra_stats *x,
47dd7a54
GC
234 struct dma_desc *p)
235{
236 int ret = csum_none;
237 struct net_device_stats *stats = (struct net_device_stats *)data;
238
239 if (unlikely(p->des01.rx.last_descriptor == 0)) {
7e848ae1 240 pr_warning("dwmac100 Error: Oversized Ethernet "
47dd7a54
GC
241 "frame spanned multiple buffers\n");
242 stats->rx_length_errors++;
243 return discard_frame;
244 }
245
246 if (unlikely(p->des01.rx.error_summary)) {
247 if (unlikely(p->des01.rx.descriptor_error))
248 x->rx_desc++;
249 if (unlikely(p->des01.rx.partial_frame_error))
250 x->rx_partial++;
251 if (unlikely(p->des01.rx.run_frame))
252 x->rx_runt++;
253 if (unlikely(p->des01.rx.frame_too_long))
254 x->rx_toolong++;
255 if (unlikely(p->des01.rx.collision)) {
256 x->rx_collision++;
257 stats->collisions++;
258 }
259 if (unlikely(p->des01.rx.crc_error)) {
260 x->rx_crc++;
261 stats->rx_crc_errors++;
262 }
263 ret = discard_frame;
264 }
265 if (unlikely(p->des01.rx.dribbling))
266 ret = discard_frame;
267
268 if (unlikely(p->des01.rx.length_error)) {
269 x->rx_lenght++;
270 ret = discard_frame;
271 }
272 if (unlikely(p->des01.rx.mii_error)) {
273 x->rx_mii++;
274 ret = discard_frame;
275 }
276 if (p->des01.rx.multicast_frame) {
277 x->rx_multicast++;
278 stats->multicast++;
279 }
280 return ret;
281}
282
7e848ae1 283static void dwmac100_irq_status(unsigned long ioaddr)
47dd7a54
GC
284{
285 return;
286}
287
7e848ae1 288static void dwmac100_set_umac_addr(unsigned long ioaddr, unsigned char *addr,
47dd7a54
GC
289 unsigned int reg_n)
290{
291 stmmac_set_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
292}
293
7e848ae1 294static void dwmac100_get_umac_addr(unsigned long ioaddr, unsigned char *addr,
47dd7a54
GC
295 unsigned int reg_n)
296{
297 stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
298}
299
7e848ae1 300static void dwmac100_set_filter(struct net_device *dev)
47dd7a54
GC
301{
302 unsigned long ioaddr = dev->base_addr;
303 u32 value = readl(ioaddr + MAC_CONTROL);
304
305 if (dev->flags & IFF_PROMISC) {
306 value |= MAC_CONTROL_PR;
307 value &= ~(MAC_CONTROL_PM | MAC_CONTROL_IF | MAC_CONTROL_HO |
308 MAC_CONTROL_HP);
309 } else if ((dev->mc_count > HASH_TABLE_SIZE)
310 || (dev->flags & IFF_ALLMULTI)) {
311 value |= MAC_CONTROL_PM;
312 value &= ~(MAC_CONTROL_PR | MAC_CONTROL_IF | MAC_CONTROL_HO);
313 writel(0xffffffff, ioaddr + MAC_HASH_HIGH);
314 writel(0xffffffff, ioaddr + MAC_HASH_LOW);
315 } else if (dev->mc_count == 0) { /* no multicast */
316 value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR | MAC_CONTROL_IF |
317 MAC_CONTROL_HO | MAC_CONTROL_HP);
318 } else {
319 int i;
320 u32 mc_filter[2];
321 struct dev_mc_list *mclist;
322
323 /* Perfect filter mode for physical address and Hash
324 filter for multicast */
325 value |= MAC_CONTROL_HP;
7e848ae1
GC
326 value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR |
327 MAC_CONTROL_IF | MAC_CONTROL_HO);
47dd7a54
GC
328
329 memset(mc_filter, 0, sizeof(mc_filter));
330 for (i = 0, mclist = dev->mc_list;
331 mclist && i < dev->mc_count; i++, mclist = mclist->next) {
332 /* The upper 6 bits of the calculated CRC are used to
333 * index the contens of the hash table */
334 int bit_nr =
335 ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
336 /* The most significant bit determines the register to
337 * use (H/L) while the other 5 bits determine the bit
338 * within the register. */
339 mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
340 }
341 writel(mc_filter[0], ioaddr + MAC_HASH_LOW);
342 writel(mc_filter[1], ioaddr + MAC_HASH_HIGH);
343 }
344
345 writel(value, ioaddr + MAC_CONTROL);
346
347 DBG(KERN_INFO "%s: CTRL reg: 0x%08x Hash regs: "
348 "HI 0x%08x, LO 0x%08x\n",
349 __func__, readl(ioaddr + MAC_CONTROL),
350 readl(ioaddr + MAC_HASH_HIGH), readl(ioaddr + MAC_HASH_LOW));
351 return;
352}
353
7e848ae1 354static void dwmac100_flow_ctrl(unsigned long ioaddr, unsigned int duplex,
47dd7a54
GC
355 unsigned int fc, unsigned int pause_time)
356{
357 unsigned int flow = MAC_FLOW_CTRL_ENABLE;
358
359 if (duplex)
360 flow |= (pause_time << MAC_FLOW_CTRL_PT_SHIFT);
361 writel(flow, ioaddr + MAC_FLOW_CTRL);
362
363 return;
364}
365
7e848ae1
GC
366/* No PMT module supported for this Ethernet Controller.
367 * Tested on ST platforms only.
368 */
369static void dwmac100_pmt(unsigned long ioaddr, unsigned long mode)
47dd7a54
GC
370{
371 return;
372}
373
7e848ae1 374static void dwmac100_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
47dd7a54
GC
375 int disable_rx_ic)
376{
377 int i;
378 for (i = 0; i < ring_size; i++) {
379 p->des01.rx.own = 1;
380 p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
381 if (i == ring_size - 1)
382 p->des01.rx.end_ring = 1;
383 if (disable_rx_ic)
384 p->des01.rx.disable_ic = 1;
385 p++;
386 }
387 return;
388}
389
7e848ae1 390static void dwmac100_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
47dd7a54
GC
391{
392 int i;
393 for (i = 0; i < ring_size; i++) {
394 p->des01.tx.own = 0;
395 if (i == ring_size - 1)
396 p->des01.tx.end_ring = 1;
397 p++;
398 }
399 return;
400}
401
7e848ae1 402static int dwmac100_get_tx_owner(struct dma_desc *p)
47dd7a54
GC
403{
404 return p->des01.tx.own;
405}
406
7e848ae1 407static int dwmac100_get_rx_owner(struct dma_desc *p)
47dd7a54
GC
408{
409 return p->des01.rx.own;
410}
411
7e848ae1 412static void dwmac100_set_tx_owner(struct dma_desc *p)
47dd7a54
GC
413{
414 p->des01.tx.own = 1;
415}
416
7e848ae1 417static void dwmac100_set_rx_owner(struct dma_desc *p)
47dd7a54
GC
418{
419 p->des01.rx.own = 1;
420}
421
7e848ae1 422static int dwmac100_get_tx_ls(struct dma_desc *p)
47dd7a54
GC
423{
424 return p->des01.tx.last_segment;
425}
426
7e848ae1 427static void dwmac100_release_tx_desc(struct dma_desc *p)
47dd7a54
GC
428{
429 int ter = p->des01.tx.end_ring;
430
431 /* clean field used within the xmit */
432 p->des01.tx.first_segment = 0;
433 p->des01.tx.last_segment = 0;
434 p->des01.tx.buffer1_size = 0;
435
436 /* clean status reported */
437 p->des01.tx.error_summary = 0;
438 p->des01.tx.underflow_error = 0;
439 p->des01.tx.no_carrier = 0;
440 p->des01.tx.loss_carrier = 0;
441 p->des01.tx.excessive_deferral = 0;
442 p->des01.tx.excessive_collisions = 0;
443 p->des01.tx.late_collision = 0;
444 p->des01.tx.heartbeat_fail = 0;
445 p->des01.tx.deferred = 0;
446
447 /* set termination field */
448 p->des01.tx.end_ring = ter;
449
450 return;
451}
452
7e848ae1 453static void dwmac100_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
47dd7a54
GC
454 int csum_flag)
455{
456 p->des01.tx.first_segment = is_fs;
457 p->des01.tx.buffer1_size = len;
458}
459
7e848ae1 460static void dwmac100_clear_tx_ic(struct dma_desc *p)
47dd7a54
GC
461{
462 p->des01.tx.interrupt = 0;
463}
464
7e848ae1 465static void dwmac100_close_tx_desc(struct dma_desc *p)
47dd7a54
GC
466{
467 p->des01.tx.last_segment = 1;
468 p->des01.tx.interrupt = 1;
469}
470
7e848ae1 471static int dwmac100_get_rx_frame_len(struct dma_desc *p)
47dd7a54
GC
472{
473 return p->des01.rx.frame_length;
474}
475
7e848ae1
GC
476struct stmmac_ops dwmac100_ops = {
477 .core_init = dwmac100_core_init,
478 .dump_regs = dwmac100_dump_mac_regs,
479 .host_irq_status = dwmac100_irq_status,
480 .set_filter = dwmac100_set_filter,
481 .flow_ctrl = dwmac100_flow_ctrl,
482 .pmt = dwmac100_pmt,
483 .set_umac_addr = dwmac100_set_umac_addr,
484 .get_umac_addr = dwmac100_get_umac_addr,
db98a0b0
GC
485};
486
7e848ae1
GC
487struct stmmac_dma_ops dwmac100_dma_ops = {
488 .init = dwmac100_dma_init,
489 .dump_regs = dwmac100_dump_dma_regs,
490 .dma_mode = dwmac100_dma_operation_mode,
491 .dma_diagnostic_fr = dwmac100_dma_diagnostic_fr,
aec7ff27
GC
492 .enable_dma_transmission = dwmac_enable_dma_transmission,
493 .enable_dma_irq = dwmac_enable_dma_irq,
494 .disable_dma_irq = dwmac_disable_dma_irq,
495 .start_tx = dwmac_dma_start_tx,
496 .stop_tx = dwmac_dma_stop_tx,
497 .start_rx = dwmac_dma_start_rx,
498 .stop_rx = dwmac_dma_stop_rx,
499 .dma_interrupt = dwmac_dma_interrupt,
db98a0b0
GC
500};
501
7e848ae1
GC
502struct stmmac_desc_ops dwmac100_desc_ops = {
503 .tx_status = dwmac100_get_tx_frame_status,
504 .rx_status = dwmac100_get_rx_frame_status,
505 .get_tx_len = dwmac100_get_tx_len,
506 .init_rx_desc = dwmac100_init_rx_desc,
507 .init_tx_desc = dwmac100_init_tx_desc,
508 .get_tx_owner = dwmac100_get_tx_owner,
509 .get_rx_owner = dwmac100_get_rx_owner,
510 .release_tx_desc = dwmac100_release_tx_desc,
511 .prepare_tx_desc = dwmac100_prepare_tx_desc,
512 .clear_tx_ic = dwmac100_clear_tx_ic,
513 .close_tx_desc = dwmac100_close_tx_desc,
514 .get_tx_ls = dwmac100_get_tx_ls,
515 .set_tx_owner = dwmac100_set_tx_owner,
516 .set_rx_owner = dwmac100_set_rx_owner,
517 .get_rx_frame_len = dwmac100_get_rx_frame_len,
47dd7a54
GC
518};
519
7e848ae1 520struct mac_device_info *dwmac100_setup(unsigned long ioaddr)
47dd7a54
GC
521{
522 struct mac_device_info *mac;
523
524 mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
525
7e848ae1 526 pr_info("\tDWMAC100\n");
47dd7a54 527
7e848ae1
GC
528 mac->mac = &dwmac100_ops;
529 mac->desc = &dwmac100_desc_ops;
530 mac->dma = &dwmac100_dma_ops;
db98a0b0
GC
531
532 mac->pmt = PMT_NOT_SUPPORTED;
533 mac->link.port = MAC_CONTROL_PS;
534 mac->link.duplex = MAC_CONTROL_F;
535 mac->link.speed = 0;
536 mac->mii.addr = MAC_MII_ADDR;
537 mac->mii.data = MAC_MII_DATA;
47dd7a54
GC
538
539 return mac;
540}