]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/mmc/sh_mmcif.c
Merge branch 'master' of git://git.denx.de/u-boot-mpc85xx
[karo-tx-uboot.git] / drivers / mmc / sh_mmcif.c
1 /*
2  * MMCIF driver.
3  *
4  * Copyright (C)  2011 Renesas Solutions Corp.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License.
9  */
10
11 #include <config.h>
12 #include <common.h>
13 #include <watchdog.h>
14 #include <command.h>
15 #include <mmc.h>
16 #include <malloc.h>
17 #include <asm/errno.h>
18 #include <asm/io.h>
19 #include "sh_mmcif.h"
20
21 #define DRIVER_NAME     "sh_mmcif"
22
23 static int sh_mmcif_intr(void *dev_id)
24 {
25         struct sh_mmcif_host *host = dev_id;
26         u32 state = 0;
27
28         state = sh_mmcif_read(&host->regs->ce_int);
29         state &= sh_mmcif_read(&host->regs->ce_int_mask);
30
31         if (state & INT_RBSYE) {
32                 sh_mmcif_write(~(INT_RBSYE | INT_CRSPE), &host->regs->ce_int);
33                 sh_mmcif_bitclr(MASK_MRBSYE, &host->regs->ce_int_mask);
34                 goto end;
35         } else if (state & INT_CRSPE) {
36                 sh_mmcif_write(~INT_CRSPE, &host->regs->ce_int);
37                 sh_mmcif_bitclr(MASK_MCRSPE, &host->regs->ce_int_mask);
38                 /* one more interrupt (INT_RBSYE) */
39                 if (sh_mmcif_read(&host->regs->ce_cmd_set) & CMD_SET_RBSY)
40                         return -EAGAIN;
41                 goto end;
42         } else if (state & INT_BUFREN) {
43                 sh_mmcif_write(~INT_BUFREN, &host->regs->ce_int);
44                 sh_mmcif_bitclr(MASK_MBUFREN, &host->regs->ce_int_mask);
45                 goto end;
46         } else if (state & INT_BUFWEN) {
47                 sh_mmcif_write(~INT_BUFWEN, &host->regs->ce_int);
48                 sh_mmcif_bitclr(MASK_MBUFWEN, &host->regs->ce_int_mask);
49                 goto end;
50         } else if (state & INT_CMD12DRE) {
51                 sh_mmcif_write(~(INT_CMD12DRE | INT_CMD12RBE | INT_CMD12CRE |
52                                   INT_BUFRE), &host->regs->ce_int);
53                 sh_mmcif_bitclr(MASK_MCMD12DRE, &host->regs->ce_int_mask);
54                 goto end;
55         } else if (state & INT_BUFRE) {
56                 sh_mmcif_write(~INT_BUFRE, &host->regs->ce_int);
57                 sh_mmcif_bitclr(MASK_MBUFRE, &host->regs->ce_int_mask);
58                 goto end;
59         } else if (state & INT_DTRANE) {
60                 sh_mmcif_write(~INT_DTRANE, &host->regs->ce_int);
61                 sh_mmcif_bitclr(MASK_MDTRANE, &host->regs->ce_int_mask);
62                 goto end;
63         } else if (state & INT_CMD12RBE) {
64                 sh_mmcif_write(~(INT_CMD12RBE | INT_CMD12CRE),
65                                 &host->regs->ce_int);
66                 sh_mmcif_bitclr(MASK_MCMD12RBE, &host->regs->ce_int_mask);
67                 goto end;
68         } else if (state & INT_ERR_STS) {
69                 /* err interrupts */
70                 sh_mmcif_write(~state, &host->regs->ce_int);
71                 sh_mmcif_bitclr(state, &host->regs->ce_int_mask);
72                 goto err;
73         } else
74                 return -EAGAIN;
75
76 err:
77         host->sd_error = 1;
78         debug("%s: int err state = %08x\n", DRIVER_NAME, state);
79 end:
80         host->wait_int = 1;
81         return 0;
82 }
83
84 static int mmcif_wait_interrupt_flag(struct sh_mmcif_host *host)
85 {
86         int timeout = 10000000;
87
88         while (1) {
89                 timeout--;
90                 if (timeout < 0) {
91                         printf("timeout\n");
92                         return 0;
93                 }
94
95                 if (!sh_mmcif_intr(host))
96                         break;
97
98                 udelay(1);      /* 1 usec */
99         }
100
101         return 1;       /* Return value: NOT 0 = complete waiting */
102 }
103
104 static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk)
105 {
106         int i;
107
108         sh_mmcif_bitclr(CLK_ENABLE, &host->regs->ce_clk_ctrl);
109         sh_mmcif_bitclr(CLK_CLEAR, &host->regs->ce_clk_ctrl);
110
111         if (!clk)
112                 return;
113         if (clk == CLKDEV_EMMC_DATA) {
114                 sh_mmcif_bitset(CLK_PCLK, &host->regs->ce_clk_ctrl);
115         } else {
116                 for (i = 1; (unsigned int)host->clk / (1 << i) >= clk; i++)
117                         ;
118                 sh_mmcif_bitset((i - 1) << 16, &host->regs->ce_clk_ctrl);
119         }
120         sh_mmcif_bitset(CLK_ENABLE, &host->regs->ce_clk_ctrl);
121 }
122
123 static void sh_mmcif_sync_reset(struct sh_mmcif_host *host)
124 {
125         u32 tmp;
126
127         tmp = sh_mmcif_read(&host->regs->ce_clk_ctrl) & (CLK_ENABLE |
128                                                          CLK_CLEAR);
129
130         sh_mmcif_write(SOFT_RST_ON, &host->regs->ce_version);
131         sh_mmcif_write(SOFT_RST_OFF, &host->regs->ce_version);
132         sh_mmcif_bitset(tmp | SRSPTO_256 | SRBSYTO_29 | SRWDTO_29 | SCCSTO_29,
133                         &host->regs->ce_clk_ctrl);
134         /* byte swap on */
135         sh_mmcif_bitset(BUF_ACC_ATYP, &host->regs->ce_buf_acc);
136 }
137
138 static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
139 {
140         u32 state1, state2;
141         int ret, timeout = 10000000;
142
143         host->sd_error = 0;
144         host->wait_int = 0;
145
146         state1 = sh_mmcif_read(&host->regs->ce_host_sts1);
147         state2 = sh_mmcif_read(&host->regs->ce_host_sts2);
148         debug("%s: ERR HOST_STS1 = %08x\n", \
149                         DRIVER_NAME, sh_mmcif_read(&host->regs->ce_host_sts1));
150         debug("%s: ERR HOST_STS2 = %08x\n", \
151                         DRIVER_NAME, sh_mmcif_read(&host->regs->ce_host_sts2));
152
153         if (state1 & STS1_CMDSEQ) {
154                 debug("%s: Forced end of command sequence\n", DRIVER_NAME);
155                 sh_mmcif_bitset(CMD_CTRL_BREAK, &host->regs->ce_cmd_ctrl);
156                 sh_mmcif_bitset(~CMD_CTRL_BREAK, &host->regs->ce_cmd_ctrl);
157                 while (1) {
158                         timeout--;
159                         if (timeout < 0) {
160                                 printf(DRIVER_NAME": Forceed end of " \
161                                         "command sequence timeout err\n");
162                                 return -EILSEQ;
163                         }
164                         if (!(sh_mmcif_read(&host->regs->ce_host_sts1)
165                                                                 & STS1_CMDSEQ))
166                                 break;
167                 }
168                 sh_mmcif_sync_reset(host);
169                 return -EILSEQ;
170         }
171
172         if (state2 & STS2_CRC_ERR)
173                 ret = -EILSEQ;
174         else if (state2 & STS2_TIMEOUT_ERR)
175                 ret = TIMEOUT;
176         else
177                 ret = -EILSEQ;
178         return ret;
179 }
180
181 static int sh_mmcif_single_read(struct sh_mmcif_host *host,
182                                 struct mmc_data *data)
183 {
184         long time;
185         u32 blocksize, i;
186         unsigned long *p = (unsigned long *)data->dest;
187
188         if ((unsigned long)p & 0x00000001) {
189                 printf("%s: The data pointer is unaligned.", __func__);
190                 return -EIO;
191         }
192
193         host->wait_int = 0;
194
195         /* buf read enable */
196         sh_mmcif_bitset(MASK_MBUFREN, &host->regs->ce_int_mask);
197         time = mmcif_wait_interrupt_flag(host);
198         if (time == 0 || host->sd_error != 0)
199                 return sh_mmcif_error_manage(host);
200
201         host->wait_int = 0;
202         blocksize = (BLOCK_SIZE_MASK &
203                         sh_mmcif_read(&host->regs->ce_block_set)) + 3;
204         for (i = 0; i < blocksize / 4; i++)
205                 *p++ = sh_mmcif_read(&host->regs->ce_data);
206
207         /* buffer read end */
208         sh_mmcif_bitset(MASK_MBUFRE, &host->regs->ce_int_mask);
209         time = mmcif_wait_interrupt_flag(host);
210         if (time == 0 || host->sd_error != 0)
211                 return sh_mmcif_error_manage(host);
212
213         host->wait_int = 0;
214         return 0;
215 }
216
217 static int sh_mmcif_multi_read(struct sh_mmcif_host *host,
218                                 struct mmc_data *data)
219 {
220         long time;
221         u32 blocksize, i, j;
222         unsigned long *p = (unsigned long *)data->dest;
223
224         if ((unsigned long)p & 0x00000001) {
225                 printf("%s: The data pointer is unaligned.", __func__);
226                 return -EIO;
227         }
228
229         host->wait_int = 0;
230         blocksize = BLOCK_SIZE_MASK & sh_mmcif_read(&host->regs->ce_block_set);
231         for (j = 0; j < data->blocks; j++) {
232                 sh_mmcif_bitset(MASK_MBUFREN, &host->regs->ce_int_mask);
233                 time = mmcif_wait_interrupt_flag(host);
234                 if (time == 0 || host->sd_error != 0)
235                         return sh_mmcif_error_manage(host);
236
237                 host->wait_int = 0;
238                 for (i = 0; i < blocksize / 4; i++)
239                         *p++ = sh_mmcif_read(&host->regs->ce_data);
240
241                 WATCHDOG_RESET();
242         }
243         return 0;
244 }
245
246 static int sh_mmcif_single_write(struct sh_mmcif_host *host,
247                                  struct mmc_data *data)
248 {
249         long time;
250         u32 blocksize, i;
251         const unsigned long *p = (unsigned long *)data->dest;
252
253         if ((unsigned long)p & 0x00000001) {
254                 printf("%s: The data pointer is unaligned.", __func__);
255                 return -EIO;
256         }
257
258         host->wait_int = 0;
259         sh_mmcif_bitset(MASK_MBUFWEN, &host->regs->ce_int_mask);
260
261         time = mmcif_wait_interrupt_flag(host);
262         if (time == 0 || host->sd_error != 0)
263                 return sh_mmcif_error_manage(host);
264
265         host->wait_int = 0;
266         blocksize = (BLOCK_SIZE_MASK &
267                         sh_mmcif_read(&host->regs->ce_block_set)) + 3;
268         for (i = 0; i < blocksize / 4; i++)
269                 sh_mmcif_write(*p++, &host->regs->ce_data);
270
271         /* buffer write end */
272         sh_mmcif_bitset(MASK_MDTRANE, &host->regs->ce_int_mask);
273
274         time = mmcif_wait_interrupt_flag(host);
275         if (time == 0 || host->sd_error != 0)
276                 return sh_mmcif_error_manage(host);
277
278         host->wait_int = 0;
279         return 0;
280 }
281
282 static int sh_mmcif_multi_write(struct sh_mmcif_host *host,
283                                 struct mmc_data *data)
284 {
285         long time;
286         u32 i, j, blocksize;
287         const unsigned long *p = (unsigned long *)data->dest;
288
289         if ((unsigned long)p & 0x00000001) {
290                 printf("%s: The data pointer is unaligned.", __func__);
291                 return -EIO;
292         }
293
294         host->wait_int = 0;
295         blocksize = BLOCK_SIZE_MASK & sh_mmcif_read(&host->regs->ce_block_set);
296         for (j = 0; j < data->blocks; j++) {
297                 sh_mmcif_bitset(MASK_MBUFWEN, &host->regs->ce_int_mask);
298
299                 time = mmcif_wait_interrupt_flag(host);
300
301                 if (time == 0 || host->sd_error != 0)
302                         return sh_mmcif_error_manage(host);
303
304                 host->wait_int = 0;
305                 for (i = 0; i < blocksize / 4; i++)
306                         sh_mmcif_write(*p++, &host->regs->ce_data);
307
308                 WATCHDOG_RESET();
309         }
310         return 0;
311 }
312
313 static void sh_mmcif_get_response(struct sh_mmcif_host *host,
314                                         struct mmc_cmd *cmd)
315 {
316         if (cmd->resp_type & MMC_RSP_136) {
317                 cmd->response[0] = sh_mmcif_read(&host->regs->ce_resp3);
318                 cmd->response[1] = sh_mmcif_read(&host->regs->ce_resp2);
319                 cmd->response[2] = sh_mmcif_read(&host->regs->ce_resp1);
320                 cmd->response[3] = sh_mmcif_read(&host->regs->ce_resp0);
321                 debug(" RESP %08x, %08x, %08x, %08x\n", cmd->response[0],
322                          cmd->response[1], cmd->response[2], cmd->response[3]);
323         } else {
324                 cmd->response[0] = sh_mmcif_read(&host->regs->ce_resp0);
325         }
326 }
327
328 static void sh_mmcif_get_cmd12response(struct sh_mmcif_host *host,
329                                         struct mmc_cmd *cmd)
330 {
331         cmd->response[0] = sh_mmcif_read(&host->regs->ce_resp_cmd12);
332 }
333
334 static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
335                                 struct mmc_data *data, struct mmc_cmd *cmd)
336 {
337         u32 tmp = 0;
338         u32 opc = cmd->cmdidx;
339
340         /* Response Type check */
341         switch (cmd->resp_type) {
342         case MMC_RSP_NONE:
343                 tmp |= CMD_SET_RTYP_NO;
344                 break;
345         case MMC_RSP_R1:
346         case MMC_RSP_R1b:
347         case MMC_RSP_R3:
348                 tmp |= CMD_SET_RTYP_6B;
349                 break;
350         case MMC_RSP_R2:
351                 tmp |= CMD_SET_RTYP_17B;
352                 break;
353         default:
354                 printf(DRIVER_NAME": Not support type response.\n");
355                 break;
356         }
357
358         /* RBSY */
359         if (opc == MMC_CMD_SWITCH)
360                 tmp |= CMD_SET_RBSY;
361
362         /* WDAT / DATW */
363         if (host->data) {
364                 tmp |= CMD_SET_WDAT;
365                 switch (host->bus_width) {
366                 case MMC_BUS_WIDTH_1:
367                         tmp |= CMD_SET_DATW_1;
368                         break;
369                 case MMC_BUS_WIDTH_4:
370                         tmp |= CMD_SET_DATW_4;
371                         break;
372                 case MMC_BUS_WIDTH_8:
373                         tmp |= CMD_SET_DATW_8;
374                         break;
375                 default:
376                         printf(DRIVER_NAME": Not support bus width.\n");
377                         break;
378                 }
379         }
380         /* DWEN */
381         if (opc == MMC_CMD_WRITE_SINGLE_BLOCK ||
382             opc == MMC_CMD_WRITE_MULTIPLE_BLOCK)
383                 tmp |= CMD_SET_DWEN;
384         /* CMLTE/CMD12EN */
385         if (opc == MMC_CMD_READ_MULTIPLE_BLOCK ||
386             opc == MMC_CMD_WRITE_MULTIPLE_BLOCK) {
387                 tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN;
388                 sh_mmcif_bitset(data->blocks << 16, &host->regs->ce_block_set);
389         }
390         /* RIDXC[1:0] check bits */
391         if (opc == MMC_CMD_SEND_OP_COND || opc == MMC_CMD_ALL_SEND_CID ||
392             opc == MMC_CMD_SEND_CSD || opc == MMC_CMD_SEND_CID)
393                 tmp |= CMD_SET_RIDXC_BITS;
394         /* RCRC7C[1:0] check bits */
395         if (opc == MMC_CMD_SEND_OP_COND)
396                 tmp |= CMD_SET_CRC7C_BITS;
397         /* RCRC7C[1:0] internal CRC7 */
398         if (opc == MMC_CMD_ALL_SEND_CID ||
399                 opc == MMC_CMD_SEND_CSD || opc == MMC_CMD_SEND_CID)
400                 tmp |= CMD_SET_CRC7C_INTERNAL;
401
402         return opc = ((opc << 24) | tmp);
403 }
404
405 static u32 sh_mmcif_data_trans(struct sh_mmcif_host *host,
406                                 struct mmc_data *data, u16 opc)
407 {
408         u32 ret;
409
410         switch (opc) {
411         case MMC_CMD_READ_MULTIPLE_BLOCK:
412                 ret = sh_mmcif_multi_read(host, data);
413                 break;
414         case MMC_CMD_WRITE_MULTIPLE_BLOCK:
415                 ret = sh_mmcif_multi_write(host, data);
416                 break;
417         case MMC_CMD_WRITE_SINGLE_BLOCK:
418                 ret = sh_mmcif_single_write(host, data);
419                 break;
420         case MMC_CMD_READ_SINGLE_BLOCK:
421         case MMC_CMD_SEND_EXT_CSD:
422                 ret = sh_mmcif_single_read(host, data);
423                 break;
424         default:
425                 printf(DRIVER_NAME": NOT SUPPORT CMD = d'%08d\n", opc);
426                 ret = -EINVAL;
427                 break;
428         }
429         return ret;
430 }
431
432 static int sh_mmcif_start_cmd(struct sh_mmcif_host *host,
433                                 struct mmc_data *data, struct mmc_cmd *cmd)
434 {
435         long time;
436         int ret = 0, mask = 0;
437         u32 opc = cmd->cmdidx;
438
439         if (opc == MMC_CMD_STOP_TRANSMISSION) {
440                 /* MMCIF sends the STOP command automatically */
441                 if (host->last_cmd == MMC_CMD_READ_MULTIPLE_BLOCK)
442                         sh_mmcif_bitset(MASK_MCMD12DRE,
443                                         &host->regs->ce_int_mask);
444                 else
445                         sh_mmcif_bitset(MASK_MCMD12RBE,
446                                         &host->regs->ce_int_mask);
447
448                 time = mmcif_wait_interrupt_flag(host);
449                 if (time == 0 || host->sd_error != 0)
450                         return sh_mmcif_error_manage(host);
451
452                 sh_mmcif_get_cmd12response(host, cmd);
453                 return 0;
454         }
455         if (opc == MMC_CMD_SWITCH)
456                 mask = MASK_MRBSYE;
457         else
458                 mask = MASK_MCRSPE;
459
460         mask |= MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR |
461                 MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR |
462                 MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO |
463                 MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO;
464
465         if (host->data) {
466                 sh_mmcif_write(0, &host->regs->ce_block_set);
467                 sh_mmcif_write(data->blocksize, &host->regs->ce_block_set);
468         }
469         opc = sh_mmcif_set_cmd(host, data, cmd);
470
471         sh_mmcif_write(INT_START_MAGIC, &host->regs->ce_int);
472         sh_mmcif_write(mask, &host->regs->ce_int_mask);
473
474         debug("CMD%d ARG:%08x\n", cmd->cmdidx, cmd->cmdarg);
475         /* set arg */
476         sh_mmcif_write(cmd->cmdarg, &host->regs->ce_arg);
477         host->wait_int = 0;
478         /* set cmd */
479         sh_mmcif_write(opc, &host->regs->ce_cmd_set);
480
481         time = mmcif_wait_interrupt_flag(host);
482         if (time == 0)
483                 return sh_mmcif_error_manage(host);
484
485         if (host->sd_error) {
486                 switch (cmd->cmdidx) {
487                 case MMC_CMD_ALL_SEND_CID:
488                 case MMC_CMD_SELECT_CARD:
489                 case MMC_CMD_APP_CMD:
490                         ret = TIMEOUT;
491                         break;
492                 default:
493                         printf(DRIVER_NAME": Cmd(d'%d) err\n", cmd->cmdidx);
494                         ret = sh_mmcif_error_manage(host);
495                         break;
496                 }
497                 host->sd_error = 0;
498                 host->wait_int = 0;
499                 return ret;
500         }
501
502         /* if no response */
503         if (!(opc & 0x00C00000))
504                 return 0;
505
506         if (host->wait_int == 1) {
507                 sh_mmcif_get_response(host, cmd);
508                 host->wait_int = 0;
509         }
510         if (host->data)
511                 ret = sh_mmcif_data_trans(host, data, cmd->cmdidx);
512         host->last_cmd = cmd->cmdidx;
513
514         return ret;
515 }
516
517 static int sh_mmcif_request(struct mmc *mmc, struct mmc_cmd *cmd,
518                             struct mmc_data *data)
519 {
520         struct sh_mmcif_host *host = mmc->priv;
521         int ret;
522
523         WATCHDOG_RESET();
524
525         switch (cmd->cmdidx) {
526         case MMC_CMD_APP_CMD:
527                 return TIMEOUT;
528         case MMC_CMD_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */
529                 if (data)
530                         /* ext_csd */
531                         break;
532                 else
533                         /* send_if_cond cmd (not support) */
534                         return TIMEOUT;
535         default:
536                 break;
537         }
538         host->sd_error = 0;
539         host->data = data;
540         ret = sh_mmcif_start_cmd(host, data, cmd);
541         host->data = NULL;
542
543         return ret;
544 }
545
546 static void sh_mmcif_set_ios(struct mmc *mmc)
547 {
548         struct sh_mmcif_host *host = mmc->priv;
549
550         if (mmc->clock)
551                 sh_mmcif_clock_control(host, mmc->clock);
552
553         if (mmc->bus_width == 8)
554                 host->bus_width = MMC_BUS_WIDTH_8;
555         else if (mmc->bus_width == 4)
556                 host->bus_width = MMC_BUS_WIDTH_4;
557         else
558                 host->bus_width = MMC_BUS_WIDTH_1;
559
560         debug("clock = %d, buswidth = %d\n", mmc->clock, mmc->bus_width);
561 }
562
563 static int sh_mmcif_init(struct mmc *mmc)
564 {
565         struct sh_mmcif_host *host = mmc->priv;
566
567         sh_mmcif_sync_reset(host);
568         sh_mmcif_write(MASK_ALL, &host->regs->ce_int_mask);
569         return 0;
570 }
571
572 static const struct mmc_ops sh_mmcif_ops = {
573         .send_cmd       = sh_mmcif_request,
574         .set_ios        = sh_mmcif_set_ios,
575         .init           = sh_mmcif_init,
576 };
577
578 static struct mmc_config sh_mmcif_cfg = {
579         .name           = DRIVER_NAME,
580         .ops            = &sh_mmcif_ops,
581         .host_caps      = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT |
582                           MMC_MODE_8BIT | MMC_MODE_HC,
583         .voltages       = MMC_VDD_32_33 | MMC_VDD_33_34,
584         .f_min          = CLKDEV_MMC_INIT,
585         .f_max          = CLKDEV_EMMC_DATA,
586         .b_max          = CONFIG_SYS_MMC_MAX_BLK_COUNT,
587 };
588
589 int mmcif_mmc_init(void)
590 {
591         struct mmc *mmc;
592         struct sh_mmcif_host *host = NULL;
593
594         host = malloc(sizeof(struct sh_mmcif_host));
595         if (!host)
596                 return -ENOMEM;
597         memset(host, 0, sizeof(*host));
598
599         host->regs = (struct sh_mmcif_regs *)CONFIG_SH_MMCIF_ADDR;
600         host->clk = CONFIG_SH_MMCIF_CLK;
601
602         mmc = mmc_create(&sh_mmcif_cfg, host);
603         if (mmc == NULL) {
604                 free(host);
605                 return -ENOMEM;
606         }
607
608         return 0;
609 }