| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * NAND flash simulator. |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 7 | 8 | * |
|---|
| 8 | 9 | * Note: NS means "NAND Simulator". |
|---|
| 9 | 10 | * Note: Input means input TO flash chip, output means output FROM chip. |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 12 | | - * under the terms of the GNU General Public License as published by the |
|---|
| 13 | | - * Free Software Foundation; either version 2, or (at your option) any later |
|---|
| 14 | | - * version. |
|---|
| 15 | | - * |
|---|
| 16 | | - * This program is distributed in the hope that it will be useful, but |
|---|
| 17 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 18 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
|---|
| 19 | | - * Public License for more details. |
|---|
| 20 | | - * |
|---|
| 21 | | - * You should have received a copy of the GNU General Public License |
|---|
| 22 | | - * along with this program; if not, write to the Free Software |
|---|
| 23 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA |
|---|
| 24 | 11 | */ |
|---|
| 25 | 12 | |
|---|
| 26 | 13 | #define pr_fmt(fmt) "[nandsim]" fmt |
|---|
| .. | .. |
|---|
| 298 | 285 | * The structure which describes all the internal simulator data. |
|---|
| 299 | 286 | */ |
|---|
| 300 | 287 | struct nandsim { |
|---|
| 288 | + struct nand_chip chip; |
|---|
| 289 | + struct nand_controller base; |
|---|
| 301 | 290 | struct mtd_partition partitions[CONFIG_NANDSIM_MAX_PARTS]; |
|---|
| 302 | 291 | unsigned int nbparts; |
|---|
| 303 | 292 | |
|---|
| .. | .. |
|---|
| 364 | 353 | void *file_buf; |
|---|
| 365 | 354 | struct page *held_pages[NS_MAX_HELD_PAGES]; |
|---|
| 366 | 355 | int held_cnt; |
|---|
| 356 | + |
|---|
| 357 | + /* debugfs entry */ |
|---|
| 358 | + struct dentry *dent; |
|---|
| 367 | 359 | }; |
|---|
| 368 | 360 | |
|---|
| 369 | 361 | /* |
|---|
| .. | .. |
|---|
| 443 | 435 | /* MTD structure for NAND controller */ |
|---|
| 444 | 436 | static struct mtd_info *nsmtd; |
|---|
| 445 | 437 | |
|---|
| 446 | | -static int nandsim_debugfs_show(struct seq_file *m, void *private) |
|---|
| 438 | +static int ns_show(struct seq_file *m, void *private) |
|---|
| 447 | 439 | { |
|---|
| 448 | 440 | unsigned long wmin = -1, wmax = 0, avg; |
|---|
| 449 | 441 | unsigned long deciles[10], decile_max[10], tot = 0; |
|---|
| .. | .. |
|---|
| 494 | 486 | |
|---|
| 495 | 487 | return 0; |
|---|
| 496 | 488 | } |
|---|
| 497 | | - |
|---|
| 498 | | -static int nandsim_debugfs_open(struct inode *inode, struct file *file) |
|---|
| 499 | | -{ |
|---|
| 500 | | - return single_open(file, nandsim_debugfs_show, inode->i_private); |
|---|
| 501 | | -} |
|---|
| 502 | | - |
|---|
| 503 | | -static const struct file_operations dfs_fops = { |
|---|
| 504 | | - .open = nandsim_debugfs_open, |
|---|
| 505 | | - .read = seq_read, |
|---|
| 506 | | - .llseek = seq_lseek, |
|---|
| 507 | | - .release = single_release, |
|---|
| 508 | | -}; |
|---|
| 489 | +DEFINE_SHOW_ATTRIBUTE(ns); |
|---|
| 509 | 490 | |
|---|
| 510 | 491 | /** |
|---|
| 511 | | - * nandsim_debugfs_create - initialize debugfs |
|---|
| 512 | | - * @dev: nandsim device description object |
|---|
| 492 | + * ns_debugfs_create - initialize debugfs |
|---|
| 493 | + * @ns: nandsim device description object |
|---|
| 513 | 494 | * |
|---|
| 514 | 495 | * This function creates all debugfs files for UBI device @ubi. Returns zero in |
|---|
| 515 | 496 | * case of success and a negative error code in case of failure. |
|---|
| 516 | 497 | */ |
|---|
| 517 | | -static int nandsim_debugfs_create(struct nandsim *dev) |
|---|
| 498 | +static int ns_debugfs_create(struct nandsim *ns) |
|---|
| 518 | 499 | { |
|---|
| 519 | 500 | struct dentry *root = nsmtd->dbg.dfs_dir; |
|---|
| 520 | | - struct dentry *dent; |
|---|
| 521 | 501 | |
|---|
| 522 | 502 | /* |
|---|
| 523 | 503 | * Just skip debugfs initialization when the debugfs directory is |
|---|
| .. | .. |
|---|
| 530 | 510 | return 0; |
|---|
| 531 | 511 | } |
|---|
| 532 | 512 | |
|---|
| 533 | | - dent = debugfs_create_file("nandsim_wear_report", S_IRUSR, |
|---|
| 534 | | - root, dev, &dfs_fops); |
|---|
| 535 | | - if (IS_ERR_OR_NULL(dent)) { |
|---|
| 513 | + ns->dent = debugfs_create_file("nandsim_wear_report", 0400, root, ns, |
|---|
| 514 | + &ns_fops); |
|---|
| 515 | + if (IS_ERR_OR_NULL(ns->dent)) { |
|---|
| 536 | 516 | NS_ERR("cannot create \"nandsim_wear_report\" debugfs entry\n"); |
|---|
| 537 | 517 | return -1; |
|---|
| 538 | 518 | } |
|---|
| 539 | 519 | |
|---|
| 540 | 520 | return 0; |
|---|
| 521 | +} |
|---|
| 522 | + |
|---|
| 523 | +static void ns_debugfs_remove(struct nandsim *ns) |
|---|
| 524 | +{ |
|---|
| 525 | + debugfs_remove_recursive(ns->dent); |
|---|
| 541 | 526 | } |
|---|
| 542 | 527 | |
|---|
| 543 | 528 | /* |
|---|
| .. | .. |
|---|
| 546 | 531 | * |
|---|
| 547 | 532 | * RETURNS: 0 if success, -ENOMEM if memory alloc fails. |
|---|
| 548 | 533 | */ |
|---|
| 549 | | -static int __init alloc_device(struct nandsim *ns) |
|---|
| 534 | +static int __init ns_alloc_device(struct nandsim *ns) |
|---|
| 550 | 535 | { |
|---|
| 551 | 536 | struct file *cfile; |
|---|
| 552 | 537 | int i, err; |
|---|
| .. | .. |
|---|
| 558 | 543 | if (!(cfile->f_mode & FMODE_CAN_READ)) { |
|---|
| 559 | 544 | NS_ERR("alloc_device: cache file not readable\n"); |
|---|
| 560 | 545 | err = -EINVAL; |
|---|
| 561 | | - goto err_close; |
|---|
| 546 | + goto err_close_filp; |
|---|
| 562 | 547 | } |
|---|
| 563 | 548 | if (!(cfile->f_mode & FMODE_CAN_WRITE)) { |
|---|
| 564 | 549 | NS_ERR("alloc_device: cache file not writeable\n"); |
|---|
| 565 | 550 | err = -EINVAL; |
|---|
| 566 | | - goto err_close; |
|---|
| 551 | + goto err_close_filp; |
|---|
| 567 | 552 | } |
|---|
| 568 | 553 | ns->pages_written = |
|---|
| 569 | 554 | vzalloc(array_size(sizeof(unsigned long), |
|---|
| .. | .. |
|---|
| 571 | 556 | if (!ns->pages_written) { |
|---|
| 572 | 557 | NS_ERR("alloc_device: unable to allocate pages written array\n"); |
|---|
| 573 | 558 | err = -ENOMEM; |
|---|
| 574 | | - goto err_close; |
|---|
| 559 | + goto err_close_filp; |
|---|
| 575 | 560 | } |
|---|
| 576 | 561 | ns->file_buf = kmalloc(ns->geom.pgszoob, GFP_KERNEL); |
|---|
| 577 | 562 | if (!ns->file_buf) { |
|---|
| 578 | 563 | NS_ERR("alloc_device: unable to allocate file buf\n"); |
|---|
| 579 | 564 | err = -ENOMEM; |
|---|
| 580 | | - goto err_free; |
|---|
| 565 | + goto err_free_pw; |
|---|
| 581 | 566 | } |
|---|
| 582 | 567 | ns->cfile = cfile; |
|---|
| 568 | + |
|---|
| 583 | 569 | return 0; |
|---|
| 570 | + |
|---|
| 571 | +err_free_pw: |
|---|
| 572 | + vfree(ns->pages_written); |
|---|
| 573 | +err_close_filp: |
|---|
| 574 | + filp_close(cfile, NULL); |
|---|
| 575 | + |
|---|
| 576 | + return err; |
|---|
| 584 | 577 | } |
|---|
| 585 | 578 | |
|---|
| 586 | 579 | ns->pages = vmalloc(array_size(sizeof(union ns_mem), ns->geom.pgnum)); |
|---|
| .. | .. |
|---|
| 595 | 588 | ns->geom.pgszoob, 0, 0, NULL); |
|---|
| 596 | 589 | if (!ns->nand_pages_slab) { |
|---|
| 597 | 590 | NS_ERR("cache_create: unable to create kmem_cache\n"); |
|---|
| 598 | | - return -ENOMEM; |
|---|
| 591 | + err = -ENOMEM; |
|---|
| 592 | + goto err_free_pg; |
|---|
| 599 | 593 | } |
|---|
| 600 | 594 | |
|---|
| 601 | 595 | return 0; |
|---|
| 602 | 596 | |
|---|
| 603 | | -err_free: |
|---|
| 604 | | - vfree(ns->pages_written); |
|---|
| 605 | | -err_close: |
|---|
| 606 | | - filp_close(cfile, NULL); |
|---|
| 597 | +err_free_pg: |
|---|
| 598 | + vfree(ns->pages); |
|---|
| 599 | + |
|---|
| 607 | 600 | return err; |
|---|
| 608 | 601 | } |
|---|
| 609 | 602 | |
|---|
| 610 | 603 | /* |
|---|
| 611 | 604 | * Free any allocated pages, and free the array of page pointers. |
|---|
| 612 | 605 | */ |
|---|
| 613 | | -static void free_device(struct nandsim *ns) |
|---|
| 606 | +static void ns_free_device(struct nandsim *ns) |
|---|
| 614 | 607 | { |
|---|
| 615 | 608 | int i; |
|---|
| 616 | 609 | |
|---|
| .. | .. |
|---|
| 632 | 625 | } |
|---|
| 633 | 626 | } |
|---|
| 634 | 627 | |
|---|
| 635 | | -static char __init *get_partition_name(int i) |
|---|
| 628 | +static char __init *ns_get_partition_name(int i) |
|---|
| 636 | 629 | { |
|---|
| 637 | 630 | return kasprintf(GFP_KERNEL, "NAND simulator partition %d", i); |
|---|
| 638 | 631 | } |
|---|
| .. | .. |
|---|
| 642 | 635 | * |
|---|
| 643 | 636 | * RETURNS: 0 if success, -ERRNO if failure. |
|---|
| 644 | 637 | */ |
|---|
| 645 | | -static int __init init_nandsim(struct mtd_info *mtd) |
|---|
| 638 | +static int __init ns_init(struct mtd_info *mtd) |
|---|
| 646 | 639 | { |
|---|
| 647 | 640 | struct nand_chip *chip = mtd_to_nand(mtd); |
|---|
| 648 | 641 | struct nandsim *ns = nand_get_controller_data(chip); |
|---|
| .. | .. |
|---|
| 654 | 647 | NS_ERR("init_nandsim: nandsim is already initialized\n"); |
|---|
| 655 | 648 | return -EIO; |
|---|
| 656 | 649 | } |
|---|
| 657 | | - |
|---|
| 658 | | - /* Force mtd to not do delays */ |
|---|
| 659 | | - chip->chip_delay = 0; |
|---|
| 660 | 650 | |
|---|
| 661 | 651 | /* Initialize the NAND flash parameters */ |
|---|
| 662 | 652 | ns->busw = chip->options & NAND_BUSWIDTH_16 ? 16 : 8; |
|---|
| .. | .. |
|---|
| 718 | 708 | NS_ERR("bad partition size.\n"); |
|---|
| 719 | 709 | return -EINVAL; |
|---|
| 720 | 710 | } |
|---|
| 721 | | - ns->partitions[i].name = get_partition_name(i); |
|---|
| 711 | + ns->partitions[i].name = ns_get_partition_name(i); |
|---|
| 722 | 712 | if (!ns->partitions[i].name) { |
|---|
| 723 | 713 | NS_ERR("unable to allocate memory.\n"); |
|---|
| 724 | 714 | return -ENOMEM; |
|---|
| .. | .. |
|---|
| 732 | 722 | if (remains) { |
|---|
| 733 | 723 | if (parts_num + 1 > ARRAY_SIZE(ns->partitions)) { |
|---|
| 734 | 724 | NS_ERR("too many partitions.\n"); |
|---|
| 735 | | - return -EINVAL; |
|---|
| 725 | + ret = -EINVAL; |
|---|
| 726 | + goto free_partition_names; |
|---|
| 736 | 727 | } |
|---|
| 737 | | - ns->partitions[i].name = get_partition_name(i); |
|---|
| 728 | + ns->partitions[i].name = ns_get_partition_name(i); |
|---|
| 738 | 729 | if (!ns->partitions[i].name) { |
|---|
| 739 | 730 | NS_ERR("unable to allocate memory.\n"); |
|---|
| 740 | | - return -ENOMEM; |
|---|
| 731 | + ret = -ENOMEM; |
|---|
| 732 | + goto free_partition_names; |
|---|
| 741 | 733 | } |
|---|
| 742 | 734 | ns->partitions[i].offset = next_offset; |
|---|
| 743 | 735 | ns->partitions[i].size = remains; |
|---|
| .. | .. |
|---|
| 764 | 756 | printk("sector address bytes: %u\n", ns->geom.secaddrbytes); |
|---|
| 765 | 757 | printk("options: %#x\n", ns->options); |
|---|
| 766 | 758 | |
|---|
| 767 | | - if ((ret = alloc_device(ns)) != 0) |
|---|
| 768 | | - return ret; |
|---|
| 759 | + ret = ns_alloc_device(ns); |
|---|
| 760 | + if (ret) |
|---|
| 761 | + goto free_partition_names; |
|---|
| 769 | 762 | |
|---|
| 770 | 763 | /* Allocate / initialize the internal buffer */ |
|---|
| 771 | 764 | ns->buf.byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL); |
|---|
| 772 | 765 | if (!ns->buf.byte) { |
|---|
| 773 | 766 | NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n", |
|---|
| 774 | 767 | ns->geom.pgszoob); |
|---|
| 775 | | - return -ENOMEM; |
|---|
| 768 | + ret = -ENOMEM; |
|---|
| 769 | + goto free_device; |
|---|
| 776 | 770 | } |
|---|
| 777 | 771 | memset(ns->buf.byte, 0xFF, ns->geom.pgszoob); |
|---|
| 778 | 772 | |
|---|
| 779 | 773 | return 0; |
|---|
| 774 | + |
|---|
| 775 | +free_device: |
|---|
| 776 | + ns_free_device(ns); |
|---|
| 777 | +free_partition_names: |
|---|
| 778 | + for (i = 0; i < ARRAY_SIZE(ns->partitions); ++i) |
|---|
| 779 | + kfree(ns->partitions[i].name); |
|---|
| 780 | + |
|---|
| 781 | + return ret; |
|---|
| 780 | 782 | } |
|---|
| 781 | 783 | |
|---|
| 782 | 784 | /* |
|---|
| 783 | 785 | * Free the nandsim structure. |
|---|
| 784 | 786 | */ |
|---|
| 785 | | -static void free_nandsim(struct nandsim *ns) |
|---|
| 787 | +static void ns_free(struct nandsim *ns) |
|---|
| 786 | 788 | { |
|---|
| 789 | + int i; |
|---|
| 790 | + |
|---|
| 791 | + for (i = 0; i < ARRAY_SIZE(ns->partitions); ++i) |
|---|
| 792 | + kfree(ns->partitions[i].name); |
|---|
| 793 | + |
|---|
| 787 | 794 | kfree(ns->buf.byte); |
|---|
| 788 | | - free_device(ns); |
|---|
| 795 | + ns_free_device(ns); |
|---|
| 789 | 796 | |
|---|
| 790 | 797 | return; |
|---|
| 791 | 798 | } |
|---|
| 792 | 799 | |
|---|
| 793 | | -static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd) |
|---|
| 800 | +static int ns_parse_badblocks(struct nandsim *ns, struct mtd_info *mtd) |
|---|
| 794 | 801 | { |
|---|
| 795 | 802 | char *w; |
|---|
| 796 | 803 | int zero_ok; |
|---|
| .. | .. |
|---|
| 818 | 825 | return 0; |
|---|
| 819 | 826 | } |
|---|
| 820 | 827 | |
|---|
| 821 | | -static int parse_weakblocks(void) |
|---|
| 828 | +static int ns_parse_weakblocks(void) |
|---|
| 822 | 829 | { |
|---|
| 823 | 830 | char *w; |
|---|
| 824 | 831 | int zero_ok; |
|---|
| .. | .. |
|---|
| 855 | 862 | return 0; |
|---|
| 856 | 863 | } |
|---|
| 857 | 864 | |
|---|
| 858 | | -static int erase_error(unsigned int erase_block_no) |
|---|
| 865 | +static int ns_erase_error(unsigned int erase_block_no) |
|---|
| 859 | 866 | { |
|---|
| 860 | 867 | struct weak_block *wb; |
|---|
| 861 | 868 | |
|---|
| .. | .. |
|---|
| 869 | 876 | return 0; |
|---|
| 870 | 877 | } |
|---|
| 871 | 878 | |
|---|
| 872 | | -static int parse_weakpages(void) |
|---|
| 879 | +static int ns_parse_weakpages(void) |
|---|
| 873 | 880 | { |
|---|
| 874 | 881 | char *w; |
|---|
| 875 | 882 | int zero_ok; |
|---|
| .. | .. |
|---|
| 906 | 913 | return 0; |
|---|
| 907 | 914 | } |
|---|
| 908 | 915 | |
|---|
| 909 | | -static int write_error(unsigned int page_no) |
|---|
| 916 | +static int ns_write_error(unsigned int page_no) |
|---|
| 910 | 917 | { |
|---|
| 911 | 918 | struct weak_page *wp; |
|---|
| 912 | 919 | |
|---|
| .. | .. |
|---|
| 920 | 927 | return 0; |
|---|
| 921 | 928 | } |
|---|
| 922 | 929 | |
|---|
| 923 | | -static int parse_gravepages(void) |
|---|
| 930 | +static int ns_parse_gravepages(void) |
|---|
| 924 | 931 | { |
|---|
| 925 | 932 | char *g; |
|---|
| 926 | 933 | int zero_ok; |
|---|
| .. | .. |
|---|
| 957 | 964 | return 0; |
|---|
| 958 | 965 | } |
|---|
| 959 | 966 | |
|---|
| 960 | | -static int read_error(unsigned int page_no) |
|---|
| 967 | +static int ns_read_error(unsigned int page_no) |
|---|
| 961 | 968 | { |
|---|
| 962 | 969 | struct grave_page *gp; |
|---|
| 963 | 970 | |
|---|
| .. | .. |
|---|
| 971 | 978 | return 0; |
|---|
| 972 | 979 | } |
|---|
| 973 | 980 | |
|---|
| 974 | | -static void free_lists(void) |
|---|
| 975 | | -{ |
|---|
| 976 | | - struct list_head *pos, *n; |
|---|
| 977 | | - list_for_each_safe(pos, n, &weak_blocks) { |
|---|
| 978 | | - list_del(pos); |
|---|
| 979 | | - kfree(list_entry(pos, struct weak_block, list)); |
|---|
| 980 | | - } |
|---|
| 981 | | - list_for_each_safe(pos, n, &weak_pages) { |
|---|
| 982 | | - list_del(pos); |
|---|
| 983 | | - kfree(list_entry(pos, struct weak_page, list)); |
|---|
| 984 | | - } |
|---|
| 985 | | - list_for_each_safe(pos, n, &grave_pages) { |
|---|
| 986 | | - list_del(pos); |
|---|
| 987 | | - kfree(list_entry(pos, struct grave_page, list)); |
|---|
| 988 | | - } |
|---|
| 989 | | - kfree(erase_block_wear); |
|---|
| 990 | | -} |
|---|
| 991 | | - |
|---|
| 992 | | -static int setup_wear_reporting(struct mtd_info *mtd) |
|---|
| 981 | +static int ns_setup_wear_reporting(struct mtd_info *mtd) |
|---|
| 993 | 982 | { |
|---|
| 994 | 983 | size_t mem; |
|---|
| 995 | 984 | |
|---|
| .. | .. |
|---|
| 1007 | 996 | return 0; |
|---|
| 1008 | 997 | } |
|---|
| 1009 | 998 | |
|---|
| 1010 | | -static void update_wear(unsigned int erase_block_no) |
|---|
| 999 | +static void ns_update_wear(unsigned int erase_block_no) |
|---|
| 1011 | 1000 | { |
|---|
| 1012 | 1001 | if (!erase_block_wear) |
|---|
| 1013 | 1002 | return; |
|---|
| .. | .. |
|---|
| 1026 | 1015 | /* |
|---|
| 1027 | 1016 | * Returns the string representation of 'state' state. |
|---|
| 1028 | 1017 | */ |
|---|
| 1029 | | -static char *get_state_name(uint32_t state) |
|---|
| 1018 | +static char *ns_get_state_name(uint32_t state) |
|---|
| 1030 | 1019 | { |
|---|
| 1031 | 1020 | switch (NS_STATE(state)) { |
|---|
| 1032 | 1021 | case STATE_CMD_READ0: |
|---|
| .. | .. |
|---|
| 1086 | 1075 | * |
|---|
| 1087 | 1076 | * RETURNS: 1 if wrong command, 0 if right. |
|---|
| 1088 | 1077 | */ |
|---|
| 1089 | | -static int check_command(int cmd) |
|---|
| 1078 | +static int ns_check_command(int cmd) |
|---|
| 1090 | 1079 | { |
|---|
| 1091 | 1080 | switch (cmd) { |
|---|
| 1092 | 1081 | |
|---|
| .. | .. |
|---|
| 1113 | 1102 | /* |
|---|
| 1114 | 1103 | * Returns state after command is accepted by command number. |
|---|
| 1115 | 1104 | */ |
|---|
| 1116 | | -static uint32_t get_state_by_command(unsigned command) |
|---|
| 1105 | +static uint32_t ns_get_state_by_command(unsigned command) |
|---|
| 1117 | 1106 | { |
|---|
| 1118 | 1107 | switch (command) { |
|---|
| 1119 | 1108 | case NAND_CMD_READ0: |
|---|
| .. | .. |
|---|
| 1151 | 1140 | /* |
|---|
| 1152 | 1141 | * Move an address byte to the correspondent internal register. |
|---|
| 1153 | 1142 | */ |
|---|
| 1154 | | -static inline void accept_addr_byte(struct nandsim *ns, u_char bt) |
|---|
| 1143 | +static inline void ns_accept_addr_byte(struct nandsim *ns, u_char bt) |
|---|
| 1155 | 1144 | { |
|---|
| 1156 | 1145 | uint byte = (uint)bt; |
|---|
| 1157 | 1146 | |
|---|
| .. | .. |
|---|
| 1169 | 1158 | /* |
|---|
| 1170 | 1159 | * Switch to STATE_READY state. |
|---|
| 1171 | 1160 | */ |
|---|
| 1172 | | -static inline void switch_to_ready_state(struct nandsim *ns, u_char status) |
|---|
| 1161 | +static inline void ns_switch_to_ready_state(struct nandsim *ns, u_char status) |
|---|
| 1173 | 1162 | { |
|---|
| 1174 | | - NS_DBG("switch_to_ready_state: switch to %s state\n", get_state_name(STATE_READY)); |
|---|
| 1163 | + NS_DBG("switch_to_ready_state: switch to %s state\n", |
|---|
| 1164 | + ns_get_state_name(STATE_READY)); |
|---|
| 1175 | 1165 | |
|---|
| 1176 | 1166 | ns->state = STATE_READY; |
|---|
| 1177 | 1167 | ns->nxstate = STATE_UNKNOWN; |
|---|
| .. | .. |
|---|
| 1228 | 1218 | * -1 - several matches. |
|---|
| 1229 | 1219 | * 0 - operation is found. |
|---|
| 1230 | 1220 | */ |
|---|
| 1231 | | -static int find_operation(struct nandsim *ns, uint32_t flag) |
|---|
| 1221 | +static int ns_find_operation(struct nandsim *ns, uint32_t flag) |
|---|
| 1232 | 1222 | { |
|---|
| 1233 | 1223 | int opsfound = 0; |
|---|
| 1234 | 1224 | int i, j, idx = 0; |
|---|
| .. | .. |
|---|
| 1281 | 1271 | ns->state = ns->op[ns->stateidx]; |
|---|
| 1282 | 1272 | ns->nxstate = ns->op[ns->stateidx + 1]; |
|---|
| 1283 | 1273 | NS_DBG("find_operation: operation found, index: %d, state: %s, nxstate %s\n", |
|---|
| 1284 | | - idx, get_state_name(ns->state), get_state_name(ns->nxstate)); |
|---|
| 1274 | + idx, ns_get_state_name(ns->state), |
|---|
| 1275 | + ns_get_state_name(ns->nxstate)); |
|---|
| 1285 | 1276 | return 0; |
|---|
| 1286 | 1277 | } |
|---|
| 1287 | 1278 | |
|---|
| .. | .. |
|---|
| 1289 | 1280 | /* Nothing was found. Try to ignore previous commands (if any) and search again */ |
|---|
| 1290 | 1281 | if (ns->npstates != 0) { |
|---|
| 1291 | 1282 | NS_DBG("find_operation: no operation found, try again with state %s\n", |
|---|
| 1292 | | - get_state_name(ns->state)); |
|---|
| 1283 | + ns_get_state_name(ns->state)); |
|---|
| 1293 | 1284 | ns->npstates = 0; |
|---|
| 1294 | | - return find_operation(ns, 0); |
|---|
| 1285 | + return ns_find_operation(ns, 0); |
|---|
| 1295 | 1286 | |
|---|
| 1296 | 1287 | } |
|---|
| 1297 | 1288 | NS_DBG("find_operation: no operations found\n"); |
|---|
| 1298 | | - switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
|---|
| 1289 | + ns_switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
|---|
| 1299 | 1290 | return -2; |
|---|
| 1300 | 1291 | } |
|---|
| 1301 | 1292 | |
|---|
| .. | .. |
|---|
| 1312 | 1303 | return -1; |
|---|
| 1313 | 1304 | } |
|---|
| 1314 | 1305 | |
|---|
| 1315 | | -static void put_pages(struct nandsim *ns) |
|---|
| 1306 | +static void ns_put_pages(struct nandsim *ns) |
|---|
| 1316 | 1307 | { |
|---|
| 1317 | 1308 | int i; |
|---|
| 1318 | 1309 | |
|---|
| .. | .. |
|---|
| 1321 | 1312 | } |
|---|
| 1322 | 1313 | |
|---|
| 1323 | 1314 | /* Get page cache pages in advance to provide NOFS memory allocation */ |
|---|
| 1324 | | -static int get_pages(struct nandsim *ns, struct file *file, size_t count, loff_t pos) |
|---|
| 1315 | +static int ns_get_pages(struct nandsim *ns, struct file *file, size_t count, |
|---|
| 1316 | + loff_t pos) |
|---|
| 1325 | 1317 | { |
|---|
| 1326 | 1318 | pgoff_t index, start_index, end_index; |
|---|
| 1327 | 1319 | struct page *page; |
|---|
| .. | .. |
|---|
| 1341 | 1333 | page = find_or_create_page(mapping, index, GFP_NOFS); |
|---|
| 1342 | 1334 | } |
|---|
| 1343 | 1335 | if (page == NULL) { |
|---|
| 1344 | | - put_pages(ns); |
|---|
| 1336 | + ns_put_pages(ns); |
|---|
| 1345 | 1337 | return -ENOMEM; |
|---|
| 1346 | 1338 | } |
|---|
| 1347 | 1339 | unlock_page(page); |
|---|
| .. | .. |
|---|
| 1351 | 1343 | return 0; |
|---|
| 1352 | 1344 | } |
|---|
| 1353 | 1345 | |
|---|
| 1354 | | -static ssize_t read_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t pos) |
|---|
| 1346 | +static ssize_t ns_read_file(struct nandsim *ns, struct file *file, void *buf, |
|---|
| 1347 | + size_t count, loff_t pos) |
|---|
| 1355 | 1348 | { |
|---|
| 1356 | 1349 | ssize_t tx; |
|---|
| 1357 | 1350 | int err; |
|---|
| 1358 | 1351 | unsigned int noreclaim_flag; |
|---|
| 1359 | 1352 | |
|---|
| 1360 | | - err = get_pages(ns, file, count, pos); |
|---|
| 1353 | + err = ns_get_pages(ns, file, count, pos); |
|---|
| 1361 | 1354 | if (err) |
|---|
| 1362 | 1355 | return err; |
|---|
| 1363 | 1356 | noreclaim_flag = memalloc_noreclaim_save(); |
|---|
| 1364 | 1357 | tx = kernel_read(file, buf, count, &pos); |
|---|
| 1365 | 1358 | memalloc_noreclaim_restore(noreclaim_flag); |
|---|
| 1366 | | - put_pages(ns); |
|---|
| 1359 | + ns_put_pages(ns); |
|---|
| 1367 | 1360 | return tx; |
|---|
| 1368 | 1361 | } |
|---|
| 1369 | 1362 | |
|---|
| 1370 | | -static ssize_t write_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t pos) |
|---|
| 1363 | +static ssize_t ns_write_file(struct nandsim *ns, struct file *file, void *buf, |
|---|
| 1364 | + size_t count, loff_t pos) |
|---|
| 1371 | 1365 | { |
|---|
| 1372 | 1366 | ssize_t tx; |
|---|
| 1373 | 1367 | int err; |
|---|
| 1374 | 1368 | unsigned int noreclaim_flag; |
|---|
| 1375 | 1369 | |
|---|
| 1376 | | - err = get_pages(ns, file, count, pos); |
|---|
| 1370 | + err = ns_get_pages(ns, file, count, pos); |
|---|
| 1377 | 1371 | if (err) |
|---|
| 1378 | 1372 | return err; |
|---|
| 1379 | 1373 | noreclaim_flag = memalloc_noreclaim_save(); |
|---|
| 1380 | 1374 | tx = kernel_write(file, buf, count, &pos); |
|---|
| 1381 | 1375 | memalloc_noreclaim_restore(noreclaim_flag); |
|---|
| 1382 | | - put_pages(ns); |
|---|
| 1376 | + ns_put_pages(ns); |
|---|
| 1383 | 1377 | return tx; |
|---|
| 1384 | 1378 | } |
|---|
| 1385 | 1379 | |
|---|
| .. | .. |
|---|
| 1399 | 1393 | return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off; |
|---|
| 1400 | 1394 | } |
|---|
| 1401 | 1395 | |
|---|
| 1402 | | -static int do_read_error(struct nandsim *ns, int num) |
|---|
| 1396 | +static int ns_do_read_error(struct nandsim *ns, int num) |
|---|
| 1403 | 1397 | { |
|---|
| 1404 | 1398 | unsigned int page_no = ns->regs.row; |
|---|
| 1405 | 1399 | |
|---|
| 1406 | | - if (read_error(page_no)) { |
|---|
| 1400 | + if (ns_read_error(page_no)) { |
|---|
| 1407 | 1401 | prandom_bytes(ns->buf.byte, num); |
|---|
| 1408 | 1402 | NS_WARN("simulating read error in page %u\n", page_no); |
|---|
| 1409 | 1403 | return 1; |
|---|
| .. | .. |
|---|
| 1411 | 1405 | return 0; |
|---|
| 1412 | 1406 | } |
|---|
| 1413 | 1407 | |
|---|
| 1414 | | -static void do_bit_flips(struct nandsim *ns, int num) |
|---|
| 1408 | +static void ns_do_bit_flips(struct nandsim *ns, int num) |
|---|
| 1415 | 1409 | { |
|---|
| 1416 | 1410 | if (bitflips && prandom_u32() < (1 << 22)) { |
|---|
| 1417 | 1411 | int flips = 1; |
|---|
| .. | .. |
|---|
| 1431 | 1425 | /* |
|---|
| 1432 | 1426 | * Fill the NAND buffer with data read from the specified page. |
|---|
| 1433 | 1427 | */ |
|---|
| 1434 | | -static void read_page(struct nandsim *ns, int num) |
|---|
| 1428 | +static void ns_read_page(struct nandsim *ns, int num) |
|---|
| 1435 | 1429 | { |
|---|
| 1436 | 1430 | union ns_mem *mypage; |
|---|
| 1437 | 1431 | |
|---|
| .. | .. |
|---|
| 1445 | 1439 | |
|---|
| 1446 | 1440 | NS_DBG("read_page: page %d written, reading from %d\n", |
|---|
| 1447 | 1441 | ns->regs.row, ns->regs.column + ns->regs.off); |
|---|
| 1448 | | - if (do_read_error(ns, num)) |
|---|
| 1442 | + if (ns_do_read_error(ns, num)) |
|---|
| 1449 | 1443 | return; |
|---|
| 1450 | 1444 | pos = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off; |
|---|
| 1451 | | - tx = read_file(ns, ns->cfile, ns->buf.byte, num, pos); |
|---|
| 1445 | + tx = ns_read_file(ns, ns->cfile, ns->buf.byte, num, |
|---|
| 1446 | + pos); |
|---|
| 1452 | 1447 | if (tx != num) { |
|---|
| 1453 | 1448 | NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx); |
|---|
| 1454 | 1449 | return; |
|---|
| 1455 | 1450 | } |
|---|
| 1456 | | - do_bit_flips(ns, num); |
|---|
| 1451 | + ns_do_bit_flips(ns, num); |
|---|
| 1457 | 1452 | } |
|---|
| 1458 | 1453 | return; |
|---|
| 1459 | 1454 | } |
|---|
| .. | .. |
|---|
| 1465 | 1460 | } else { |
|---|
| 1466 | 1461 | NS_DBG("read_page: page %d allocated, reading from %d\n", |
|---|
| 1467 | 1462 | ns->regs.row, ns->regs.column + ns->regs.off); |
|---|
| 1468 | | - if (do_read_error(ns, num)) |
|---|
| 1463 | + if (ns_do_read_error(ns, num)) |
|---|
| 1469 | 1464 | return; |
|---|
| 1470 | 1465 | memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num); |
|---|
| 1471 | | - do_bit_flips(ns, num); |
|---|
| 1466 | + ns_do_bit_flips(ns, num); |
|---|
| 1472 | 1467 | } |
|---|
| 1473 | 1468 | } |
|---|
| 1474 | 1469 | |
|---|
| 1475 | 1470 | /* |
|---|
| 1476 | 1471 | * Erase all pages in the specified sector. |
|---|
| 1477 | 1472 | */ |
|---|
| 1478 | | -static void erase_sector(struct nandsim *ns) |
|---|
| 1473 | +static void ns_erase_sector(struct nandsim *ns) |
|---|
| 1479 | 1474 | { |
|---|
| 1480 | 1475 | union ns_mem *mypage; |
|---|
| 1481 | 1476 | int i; |
|---|
| .. | .. |
|---|
| 1503 | 1498 | /* |
|---|
| 1504 | 1499 | * Program the specified page with the contents from the NAND buffer. |
|---|
| 1505 | 1500 | */ |
|---|
| 1506 | | -static int prog_page(struct nandsim *ns, int num) |
|---|
| 1501 | +static int ns_prog_page(struct nandsim *ns, int num) |
|---|
| 1507 | 1502 | { |
|---|
| 1508 | 1503 | int i; |
|---|
| 1509 | 1504 | union ns_mem *mypage; |
|---|
| .. | .. |
|---|
| 1522 | 1517 | memset(ns->file_buf, 0xff, ns->geom.pgszoob); |
|---|
| 1523 | 1518 | } else { |
|---|
| 1524 | 1519 | all = 0; |
|---|
| 1525 | | - tx = read_file(ns, ns->cfile, pg_off, num, off); |
|---|
| 1520 | + tx = ns_read_file(ns, ns->cfile, pg_off, num, off); |
|---|
| 1526 | 1521 | if (tx != num) { |
|---|
| 1527 | 1522 | NS_ERR("prog_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx); |
|---|
| 1528 | 1523 | return -1; |
|---|
| .. | .. |
|---|
| 1532 | 1527 | pg_off[i] &= ns->buf.byte[i]; |
|---|
| 1533 | 1528 | if (all) { |
|---|
| 1534 | 1529 | loff_t pos = (loff_t)ns->regs.row * ns->geom.pgszoob; |
|---|
| 1535 | | - tx = write_file(ns, ns->cfile, ns->file_buf, ns->geom.pgszoob, pos); |
|---|
| 1530 | + tx = ns_write_file(ns, ns->cfile, ns->file_buf, |
|---|
| 1531 | + ns->geom.pgszoob, pos); |
|---|
| 1536 | 1532 | if (tx != ns->geom.pgszoob) { |
|---|
| 1537 | 1533 | NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx); |
|---|
| 1538 | 1534 | return -1; |
|---|
| 1539 | 1535 | } |
|---|
| 1540 | 1536 | __set_bit(ns->regs.row, ns->pages_written); |
|---|
| 1541 | 1537 | } else { |
|---|
| 1542 | | - tx = write_file(ns, ns->cfile, pg_off, num, off); |
|---|
| 1538 | + tx = ns_write_file(ns, ns->cfile, pg_off, num, off); |
|---|
| 1543 | 1539 | if (tx != num) { |
|---|
| 1544 | 1540 | NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx); |
|---|
| 1545 | 1541 | return -1; |
|---|
| .. | .. |
|---|
| 1577 | 1573 | * |
|---|
| 1578 | 1574 | * RETURNS: 0 if success, -1 if error. |
|---|
| 1579 | 1575 | */ |
|---|
| 1580 | | -static int do_state_action(struct nandsim *ns, uint32_t action) |
|---|
| 1576 | +static int ns_do_state_action(struct nandsim *ns, uint32_t action) |
|---|
| 1581 | 1577 | { |
|---|
| 1582 | 1578 | int num; |
|---|
| 1583 | 1579 | int busdiv = ns->busw == 8 ? 1 : 2; |
|---|
| .. | .. |
|---|
| 1604 | 1600 | break; |
|---|
| 1605 | 1601 | } |
|---|
| 1606 | 1602 | num = ns->geom.pgszoob - ns->regs.off - ns->regs.column; |
|---|
| 1607 | | - read_page(ns, num); |
|---|
| 1603 | + ns_read_page(ns, num); |
|---|
| 1608 | 1604 | |
|---|
| 1609 | 1605 | NS_DBG("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n", |
|---|
| 1610 | 1606 | num, NS_RAW_OFFSET(ns) + ns->regs.off); |
|---|
| .. | .. |
|---|
| 1647 | 1643 | ns->regs.row, NS_RAW_OFFSET(ns)); |
|---|
| 1648 | 1644 | NS_LOG("erase sector %u\n", erase_block_no); |
|---|
| 1649 | 1645 | |
|---|
| 1650 | | - erase_sector(ns); |
|---|
| 1646 | + ns_erase_sector(ns); |
|---|
| 1651 | 1647 | |
|---|
| 1652 | 1648 | NS_MDELAY(erase_delay); |
|---|
| 1653 | 1649 | |
|---|
| 1654 | 1650 | if (erase_block_wear) |
|---|
| 1655 | | - update_wear(erase_block_no); |
|---|
| 1651 | + ns_update_wear(erase_block_no); |
|---|
| 1656 | 1652 | |
|---|
| 1657 | | - if (erase_error(erase_block_no)) { |
|---|
| 1653 | + if (ns_erase_error(erase_block_no)) { |
|---|
| 1658 | 1654 | NS_WARN("simulating erase failure in erase block %u\n", erase_block_no); |
|---|
| 1659 | 1655 | return -1; |
|---|
| 1660 | 1656 | } |
|---|
| .. | .. |
|---|
| 1678 | 1674 | return -1; |
|---|
| 1679 | 1675 | } |
|---|
| 1680 | 1676 | |
|---|
| 1681 | | - if (prog_page(ns, num) == -1) |
|---|
| 1677 | + if (ns_prog_page(ns, num) == -1) |
|---|
| 1682 | 1678 | return -1; |
|---|
| 1683 | 1679 | |
|---|
| 1684 | 1680 | page_no = ns->regs.row; |
|---|
| .. | .. |
|---|
| 1690 | 1686 | NS_UDELAY(programm_delay); |
|---|
| 1691 | 1687 | NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv); |
|---|
| 1692 | 1688 | |
|---|
| 1693 | | - if (write_error(page_no)) { |
|---|
| 1689 | + if (ns_write_error(page_no)) { |
|---|
| 1694 | 1690 | NS_WARN("simulating write failure in page %u\n", page_no); |
|---|
| 1695 | 1691 | return -1; |
|---|
| 1696 | 1692 | } |
|---|
| .. | .. |
|---|
| 1727 | 1723 | /* |
|---|
| 1728 | 1724 | * Switch simulator's state. |
|---|
| 1729 | 1725 | */ |
|---|
| 1730 | | -static void switch_state(struct nandsim *ns) |
|---|
| 1726 | +static void ns_switch_state(struct nandsim *ns) |
|---|
| 1731 | 1727 | { |
|---|
| 1732 | 1728 | if (ns->op) { |
|---|
| 1733 | 1729 | /* |
|---|
| .. | .. |
|---|
| 1741 | 1737 | |
|---|
| 1742 | 1738 | NS_DBG("switch_state: operation is known, switch to the next state, " |
|---|
| 1743 | 1739 | "state: %s, nxstate: %s\n", |
|---|
| 1744 | | - get_state_name(ns->state), get_state_name(ns->nxstate)); |
|---|
| 1740 | + ns_get_state_name(ns->state), |
|---|
| 1741 | + ns_get_state_name(ns->nxstate)); |
|---|
| 1745 | 1742 | |
|---|
| 1746 | 1743 | /* See, whether we need to do some action */ |
|---|
| 1747 | | - if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) { |
|---|
| 1748 | | - switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
|---|
| 1744 | + if ((ns->state & ACTION_MASK) && |
|---|
| 1745 | + ns_do_state_action(ns, ns->state) < 0) { |
|---|
| 1746 | + ns_switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
|---|
| 1749 | 1747 | return; |
|---|
| 1750 | 1748 | } |
|---|
| 1751 | 1749 | |
|---|
| .. | .. |
|---|
| 1759 | 1757 | * The only event causing the switch_state function to |
|---|
| 1760 | 1758 | * be called with yet unknown operation is new command. |
|---|
| 1761 | 1759 | */ |
|---|
| 1762 | | - ns->state = get_state_by_command(ns->regs.command); |
|---|
| 1760 | + ns->state = ns_get_state_by_command(ns->regs.command); |
|---|
| 1763 | 1761 | |
|---|
| 1764 | 1762 | NS_DBG("switch_state: operation is unknown, try to find it\n"); |
|---|
| 1765 | 1763 | |
|---|
| 1766 | | - if (find_operation(ns, 0) != 0) |
|---|
| 1764 | + if (ns_find_operation(ns, 0)) |
|---|
| 1767 | 1765 | return; |
|---|
| 1768 | 1766 | |
|---|
| 1769 | | - if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) { |
|---|
| 1770 | | - switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
|---|
| 1767 | + if ((ns->state & ACTION_MASK) && |
|---|
| 1768 | + ns_do_state_action(ns, ns->state) < 0) { |
|---|
| 1769 | + ns_switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
|---|
| 1771 | 1770 | return; |
|---|
| 1772 | 1771 | } |
|---|
| 1773 | 1772 | } |
|---|
| .. | .. |
|---|
| 1795 | 1794 | |
|---|
| 1796 | 1795 | NS_DBG("switch_state: operation complete, switch to STATE_READY state\n"); |
|---|
| 1797 | 1796 | |
|---|
| 1798 | | - switch_to_ready_state(ns, status); |
|---|
| 1797 | + ns_switch_to_ready_state(ns, status); |
|---|
| 1799 | 1798 | |
|---|
| 1800 | 1799 | return; |
|---|
| 1801 | 1800 | } else if (ns->nxstate & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK)) { |
|---|
| .. | .. |
|---|
| 1809 | 1808 | |
|---|
| 1810 | 1809 | NS_DBG("switch_state: the next state is data I/O, switch, " |
|---|
| 1811 | 1810 | "state: %s, nxstate: %s\n", |
|---|
| 1812 | | - get_state_name(ns->state), get_state_name(ns->nxstate)); |
|---|
| 1811 | + ns_get_state_name(ns->state), |
|---|
| 1812 | + ns_get_state_name(ns->nxstate)); |
|---|
| 1813 | 1813 | |
|---|
| 1814 | 1814 | /* |
|---|
| 1815 | 1815 | * Set the internal register to the count of bytes which |
|---|
| .. | .. |
|---|
| 1872 | 1872 | } |
|---|
| 1873 | 1873 | } |
|---|
| 1874 | 1874 | |
|---|
| 1875 | | -static u_char ns_nand_read_byte(struct mtd_info *mtd) |
|---|
| 1875 | +static u_char ns_nand_read_byte(struct nand_chip *chip) |
|---|
| 1876 | 1876 | { |
|---|
| 1877 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
|---|
| 1878 | 1877 | struct nandsim *ns = nand_get_controller_data(chip); |
|---|
| 1879 | 1878 | u_char outb = 0x00; |
|---|
| 1880 | 1879 | |
|---|
| .. | .. |
|---|
| 1888 | 1887 | return outb; |
|---|
| 1889 | 1888 | } |
|---|
| 1890 | 1889 | if (!(ns->state & STATE_DATAOUT_MASK)) { |
|---|
| 1891 | | - NS_WARN("read_byte: unexpected data output cycle, state is %s " |
|---|
| 1892 | | - "return %#x\n", get_state_name(ns->state), (uint)outb); |
|---|
| 1890 | + NS_WARN("read_byte: unexpected data output cycle, state is %s return %#x\n", |
|---|
| 1891 | + ns_get_state_name(ns->state), (uint)outb); |
|---|
| 1893 | 1892 | return outb; |
|---|
| 1894 | 1893 | } |
|---|
| 1895 | 1894 | |
|---|
| .. | .. |
|---|
| 1928 | 1927 | NS_DBG("read_byte: all bytes were read\n"); |
|---|
| 1929 | 1928 | |
|---|
| 1930 | 1929 | if (NS_STATE(ns->nxstate) == STATE_READY) |
|---|
| 1931 | | - switch_state(ns); |
|---|
| 1930 | + ns_switch_state(ns); |
|---|
| 1932 | 1931 | } |
|---|
| 1933 | 1932 | |
|---|
| 1934 | 1933 | return outb; |
|---|
| 1935 | 1934 | } |
|---|
| 1936 | 1935 | |
|---|
| 1937 | | -static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte) |
|---|
| 1936 | +static void ns_nand_write_byte(struct nand_chip *chip, u_char byte) |
|---|
| 1938 | 1937 | { |
|---|
| 1939 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
|---|
| 1940 | 1938 | struct nandsim *ns = nand_get_controller_data(chip); |
|---|
| 1941 | 1939 | |
|---|
| 1942 | 1940 | /* Sanity and correctness checks */ |
|---|
| .. | .. |
|---|
| 1956 | 1954 | |
|---|
| 1957 | 1955 | if (byte == NAND_CMD_RESET) { |
|---|
| 1958 | 1956 | NS_LOG("reset chip\n"); |
|---|
| 1959 | | - switch_to_ready_state(ns, NS_STATUS_OK(ns)); |
|---|
| 1957 | + ns_switch_to_ready_state(ns, NS_STATUS_OK(ns)); |
|---|
| 1960 | 1958 | return; |
|---|
| 1961 | 1959 | } |
|---|
| 1962 | 1960 | |
|---|
| 1963 | 1961 | /* Check that the command byte is correct */ |
|---|
| 1964 | | - if (check_command(byte)) { |
|---|
| 1962 | + if (ns_check_command(byte)) { |
|---|
| 1965 | 1963 | NS_ERR("write_byte: unknown command %#x\n", (uint)byte); |
|---|
| 1966 | 1964 | return; |
|---|
| 1967 | 1965 | } |
|---|
| .. | .. |
|---|
| 1970 | 1968 | || NS_STATE(ns->state) == STATE_DATAOUT) { |
|---|
| 1971 | 1969 | int row = ns->regs.row; |
|---|
| 1972 | 1970 | |
|---|
| 1973 | | - switch_state(ns); |
|---|
| 1971 | + ns_switch_state(ns); |
|---|
| 1974 | 1972 | if (byte == NAND_CMD_RNDOUT) |
|---|
| 1975 | 1973 | ns->regs.row = row; |
|---|
| 1976 | 1974 | } |
|---|
| .. | .. |
|---|
| 1985 | 1983 | * was expected but command was input. In this case ignore |
|---|
| 1986 | 1984 | * previous command(s)/state(s) and accept the last one. |
|---|
| 1987 | 1985 | */ |
|---|
| 1988 | | - NS_WARN("write_byte: command (%#x) wasn't expected, expected state is %s, " |
|---|
| 1989 | | - "ignore previous states\n", (uint)byte, get_state_name(ns->nxstate)); |
|---|
| 1986 | + NS_WARN("write_byte: command (%#x) wasn't expected, expected state is %s, ignore previous states\n", |
|---|
| 1987 | + (uint)byte, |
|---|
| 1988 | + ns_get_state_name(ns->nxstate)); |
|---|
| 1990 | 1989 | } |
|---|
| 1991 | | - switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
|---|
| 1990 | + ns_switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
|---|
| 1992 | 1991 | } |
|---|
| 1993 | 1992 | |
|---|
| 1994 | 1993 | NS_DBG("command byte corresponding to %s state accepted\n", |
|---|
| 1995 | | - get_state_name(get_state_by_command(byte))); |
|---|
| 1994 | + ns_get_state_name(ns_get_state_by_command(byte))); |
|---|
| 1996 | 1995 | ns->regs.command = byte; |
|---|
| 1997 | | - switch_state(ns); |
|---|
| 1996 | + ns_switch_state(ns); |
|---|
| 1998 | 1997 | |
|---|
| 1999 | 1998 | } else if (ns->lines.ale == 1) { |
|---|
| 2000 | 1999 | /* |
|---|
| .. | .. |
|---|
| 2005 | 2004 | |
|---|
| 2006 | 2005 | NS_DBG("write_byte: operation isn't known yet, identify it\n"); |
|---|
| 2007 | 2006 | |
|---|
| 2008 | | - if (find_operation(ns, 1) < 0) |
|---|
| 2007 | + if (ns_find_operation(ns, 1) < 0) |
|---|
| 2009 | 2008 | return; |
|---|
| 2010 | 2009 | |
|---|
| 2011 | | - if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) { |
|---|
| 2012 | | - switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
|---|
| 2010 | + if ((ns->state & ACTION_MASK) && |
|---|
| 2011 | + ns_do_state_action(ns, ns->state) < 0) { |
|---|
| 2012 | + ns_switch_to_ready_state(ns, |
|---|
| 2013 | + NS_STATUS_FAILED(ns)); |
|---|
| 2013 | 2014 | return; |
|---|
| 2014 | 2015 | } |
|---|
| 2015 | 2016 | |
|---|
| .. | .. |
|---|
| 2031 | 2032 | |
|---|
| 2032 | 2033 | /* Check that chip is expecting address */ |
|---|
| 2033 | 2034 | if (!(ns->nxstate & STATE_ADDR_MASK)) { |
|---|
| 2034 | | - NS_ERR("write_byte: address (%#x) isn't expected, expected state is %s, " |
|---|
| 2035 | | - "switch to STATE_READY\n", (uint)byte, get_state_name(ns->nxstate)); |
|---|
| 2036 | | - switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
|---|
| 2035 | + NS_ERR("write_byte: address (%#x) isn't expected, expected state is %s, switch to STATE_READY\n", |
|---|
| 2036 | + (uint)byte, ns_get_state_name(ns->nxstate)); |
|---|
| 2037 | + ns_switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
|---|
| 2037 | 2038 | return; |
|---|
| 2038 | 2039 | } |
|---|
| 2039 | 2040 | |
|---|
| 2040 | 2041 | /* Check if this is expected byte */ |
|---|
| 2041 | 2042 | if (ns->regs.count == ns->regs.num) { |
|---|
| 2042 | 2043 | NS_ERR("write_byte: no more address bytes expected\n"); |
|---|
| 2043 | | - switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
|---|
| 2044 | + ns_switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
|---|
| 2044 | 2045 | return; |
|---|
| 2045 | 2046 | } |
|---|
| 2046 | 2047 | |
|---|
| 2047 | | - accept_addr_byte(ns, byte); |
|---|
| 2048 | + ns_accept_addr_byte(ns, byte); |
|---|
| 2048 | 2049 | |
|---|
| 2049 | 2050 | ns->regs.count += 1; |
|---|
| 2050 | 2051 | |
|---|
| .. | .. |
|---|
| 2053 | 2054 | |
|---|
| 2054 | 2055 | if (ns->regs.count == ns->regs.num) { |
|---|
| 2055 | 2056 | NS_DBG("address (%#x, %#x) is accepted\n", ns->regs.row, ns->regs.column); |
|---|
| 2056 | | - switch_state(ns); |
|---|
| 2057 | + ns_switch_state(ns); |
|---|
| 2057 | 2058 | } |
|---|
| 2058 | 2059 | |
|---|
| 2059 | 2060 | } else { |
|---|
| .. | .. |
|---|
| 2063 | 2064 | |
|---|
| 2064 | 2065 | /* Check that chip is expecting data input */ |
|---|
| 2065 | 2066 | if (!(ns->state & STATE_DATAIN_MASK)) { |
|---|
| 2066 | | - NS_ERR("write_byte: data input (%#x) isn't expected, state is %s, " |
|---|
| 2067 | | - "switch to %s\n", (uint)byte, |
|---|
| 2068 | | - get_state_name(ns->state), get_state_name(STATE_READY)); |
|---|
| 2069 | | - switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
|---|
| 2067 | + NS_ERR("write_byte: data input (%#x) isn't expected, state is %s, switch to %s\n", |
|---|
| 2068 | + (uint)byte, ns_get_state_name(ns->state), |
|---|
| 2069 | + ns_get_state_name(STATE_READY)); |
|---|
| 2070 | + ns_switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
|---|
| 2070 | 2071 | return; |
|---|
| 2071 | 2072 | } |
|---|
| 2072 | 2073 | |
|---|
| .. | .. |
|---|
| 2089 | 2090 | return; |
|---|
| 2090 | 2091 | } |
|---|
| 2091 | 2092 | |
|---|
| 2092 | | -static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask) |
|---|
| 2093 | +static void ns_nand_write_buf(struct nand_chip *chip, const u_char *buf, |
|---|
| 2094 | + int len) |
|---|
| 2093 | 2095 | { |
|---|
| 2094 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
|---|
| 2095 | | - struct nandsim *ns = nand_get_controller_data(chip); |
|---|
| 2096 | | - |
|---|
| 2097 | | - ns->lines.cle = bitmask & NAND_CLE ? 1 : 0; |
|---|
| 2098 | | - ns->lines.ale = bitmask & NAND_ALE ? 1 : 0; |
|---|
| 2099 | | - ns->lines.ce = bitmask & NAND_NCE ? 1 : 0; |
|---|
| 2100 | | - |
|---|
| 2101 | | - if (cmd != NAND_CMD_NONE) |
|---|
| 2102 | | - ns_nand_write_byte(mtd, cmd); |
|---|
| 2103 | | -} |
|---|
| 2104 | | - |
|---|
| 2105 | | -static int ns_device_ready(struct mtd_info *mtd) |
|---|
| 2106 | | -{ |
|---|
| 2107 | | - NS_DBG("device_ready\n"); |
|---|
| 2108 | | - return 1; |
|---|
| 2109 | | -} |
|---|
| 2110 | | - |
|---|
| 2111 | | -static uint16_t ns_nand_read_word(struct mtd_info *mtd) |
|---|
| 2112 | | -{ |
|---|
| 2113 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
|---|
| 2114 | | - |
|---|
| 2115 | | - NS_DBG("read_word\n"); |
|---|
| 2116 | | - |
|---|
| 2117 | | - return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8); |
|---|
| 2118 | | -} |
|---|
| 2119 | | - |
|---|
| 2120 | | -static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) |
|---|
| 2121 | | -{ |
|---|
| 2122 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
|---|
| 2123 | 2096 | struct nandsim *ns = nand_get_controller_data(chip); |
|---|
| 2124 | 2097 | |
|---|
| 2125 | 2098 | /* Check that chip is expecting data input */ |
|---|
| 2126 | 2099 | if (!(ns->state & STATE_DATAIN_MASK)) { |
|---|
| 2127 | | - NS_ERR("write_buf: data input isn't expected, state is %s, " |
|---|
| 2128 | | - "switch to STATE_READY\n", get_state_name(ns->state)); |
|---|
| 2129 | | - switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
|---|
| 2100 | + NS_ERR("write_buf: data input isn't expected, state is %s, switch to STATE_READY\n", |
|---|
| 2101 | + ns_get_state_name(ns->state)); |
|---|
| 2102 | + ns_switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
|---|
| 2130 | 2103 | return; |
|---|
| 2131 | 2104 | } |
|---|
| 2132 | 2105 | |
|---|
| 2133 | 2106 | /* Check if these are expected bytes */ |
|---|
| 2134 | 2107 | if (ns->regs.count + len > ns->regs.num) { |
|---|
| 2135 | 2108 | NS_ERR("write_buf: too many input bytes\n"); |
|---|
| 2136 | | - switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
|---|
| 2109 | + ns_switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
|---|
| 2137 | 2110 | return; |
|---|
| 2138 | 2111 | } |
|---|
| 2139 | 2112 | |
|---|
| .. | .. |
|---|
| 2145 | 2118 | } |
|---|
| 2146 | 2119 | } |
|---|
| 2147 | 2120 | |
|---|
| 2148 | | -static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) |
|---|
| 2121 | +static void ns_nand_read_buf(struct nand_chip *chip, u_char *buf, int len) |
|---|
| 2149 | 2122 | { |
|---|
| 2150 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
|---|
| 2151 | 2123 | struct nandsim *ns = nand_get_controller_data(chip); |
|---|
| 2152 | 2124 | |
|---|
| 2153 | 2125 | /* Sanity and correctness checks */ |
|---|
| .. | .. |
|---|
| 2161 | 2133 | } |
|---|
| 2162 | 2134 | if (!(ns->state & STATE_DATAOUT_MASK)) { |
|---|
| 2163 | 2135 | NS_WARN("read_buf: unexpected data output cycle, current state is %s\n", |
|---|
| 2164 | | - get_state_name(ns->state)); |
|---|
| 2136 | + ns_get_state_name(ns->state)); |
|---|
| 2165 | 2137 | return; |
|---|
| 2166 | 2138 | } |
|---|
| 2167 | 2139 | |
|---|
| .. | .. |
|---|
| 2169 | 2141 | int i; |
|---|
| 2170 | 2142 | |
|---|
| 2171 | 2143 | for (i = 0; i < len; i++) |
|---|
| 2172 | | - buf[i] = mtd_to_nand(mtd)->read_byte(mtd); |
|---|
| 2144 | + buf[i] = ns_nand_read_byte(chip); |
|---|
| 2173 | 2145 | |
|---|
| 2174 | 2146 | return; |
|---|
| 2175 | 2147 | } |
|---|
| .. | .. |
|---|
| 2177 | 2149 | /* Check if these are expected bytes */ |
|---|
| 2178 | 2150 | if (ns->regs.count + len > ns->regs.num) { |
|---|
| 2179 | 2151 | NS_ERR("read_buf: too many bytes to read\n"); |
|---|
| 2180 | | - switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
|---|
| 2152 | + ns_switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
|---|
| 2181 | 2153 | return; |
|---|
| 2182 | 2154 | } |
|---|
| 2183 | 2155 | |
|---|
| .. | .. |
|---|
| 2186 | 2158 | |
|---|
| 2187 | 2159 | if (ns->regs.count == ns->regs.num) { |
|---|
| 2188 | 2160 | if (NS_STATE(ns->nxstate) == STATE_READY) |
|---|
| 2189 | | - switch_state(ns); |
|---|
| 2161 | + ns_switch_state(ns); |
|---|
| 2190 | 2162 | } |
|---|
| 2191 | 2163 | |
|---|
| 2192 | 2164 | return; |
|---|
| 2193 | 2165 | } |
|---|
| 2194 | 2166 | |
|---|
| 2167 | +static int ns_exec_op(struct nand_chip *chip, const struct nand_operation *op, |
|---|
| 2168 | + bool check_only) |
|---|
| 2169 | +{ |
|---|
| 2170 | + int i; |
|---|
| 2171 | + unsigned int op_id; |
|---|
| 2172 | + const struct nand_op_instr *instr = NULL; |
|---|
| 2173 | + struct nandsim *ns = nand_get_controller_data(chip); |
|---|
| 2174 | + |
|---|
| 2175 | + if (check_only) |
|---|
| 2176 | + return 0; |
|---|
| 2177 | + |
|---|
| 2178 | + ns->lines.ce = 1; |
|---|
| 2179 | + |
|---|
| 2180 | + for (op_id = 0; op_id < op->ninstrs; op_id++) { |
|---|
| 2181 | + instr = &op->instrs[op_id]; |
|---|
| 2182 | + ns->lines.cle = 0; |
|---|
| 2183 | + ns->lines.ale = 0; |
|---|
| 2184 | + |
|---|
| 2185 | + switch (instr->type) { |
|---|
| 2186 | + case NAND_OP_CMD_INSTR: |
|---|
| 2187 | + ns->lines.cle = 1; |
|---|
| 2188 | + ns_nand_write_byte(chip, instr->ctx.cmd.opcode); |
|---|
| 2189 | + break; |
|---|
| 2190 | + case NAND_OP_ADDR_INSTR: |
|---|
| 2191 | + ns->lines.ale = 1; |
|---|
| 2192 | + for (i = 0; i < instr->ctx.addr.naddrs; i++) |
|---|
| 2193 | + ns_nand_write_byte(chip, instr->ctx.addr.addrs[i]); |
|---|
| 2194 | + break; |
|---|
| 2195 | + case NAND_OP_DATA_IN_INSTR: |
|---|
| 2196 | + ns_nand_read_buf(chip, instr->ctx.data.buf.in, instr->ctx.data.len); |
|---|
| 2197 | + break; |
|---|
| 2198 | + case NAND_OP_DATA_OUT_INSTR: |
|---|
| 2199 | + ns_nand_write_buf(chip, instr->ctx.data.buf.out, instr->ctx.data.len); |
|---|
| 2200 | + break; |
|---|
| 2201 | + case NAND_OP_WAITRDY_INSTR: |
|---|
| 2202 | + /* we are always ready */ |
|---|
| 2203 | + break; |
|---|
| 2204 | + } |
|---|
| 2205 | + } |
|---|
| 2206 | + |
|---|
| 2207 | + return 0; |
|---|
| 2208 | +} |
|---|
| 2209 | + |
|---|
| 2195 | 2210 | static int ns_attach_chip(struct nand_chip *chip) |
|---|
| 2196 | 2211 | { |
|---|
| 2197 | 2212 | unsigned int eccsteps, eccbytes; |
|---|
| 2213 | + |
|---|
| 2214 | + chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; |
|---|
| 2215 | + chip->ecc.algo = bch ? NAND_ECC_ALGO_BCH : NAND_ECC_ALGO_HAMMING; |
|---|
| 2198 | 2216 | |
|---|
| 2199 | 2217 | if (!bch) |
|---|
| 2200 | 2218 | return 0; |
|---|
| .. | .. |
|---|
| 2219 | 2237 | return -EINVAL; |
|---|
| 2220 | 2238 | } |
|---|
| 2221 | 2239 | |
|---|
| 2222 | | - chip->ecc.mode = NAND_ECC_SOFT; |
|---|
| 2223 | | - chip->ecc.algo = NAND_ECC_BCH; |
|---|
| 2224 | 2240 | chip->ecc.size = 512; |
|---|
| 2225 | 2241 | chip->ecc.strength = bch; |
|---|
| 2226 | 2242 | chip->ecc.bytes = eccbytes; |
|---|
| .. | .. |
|---|
| 2232 | 2248 | |
|---|
| 2233 | 2249 | static const struct nand_controller_ops ns_controller_ops = { |
|---|
| 2234 | 2250 | .attach_chip = ns_attach_chip, |
|---|
| 2251 | + .exec_op = ns_exec_op, |
|---|
| 2235 | 2252 | }; |
|---|
| 2236 | 2253 | |
|---|
| 2237 | 2254 | /* |
|---|
| .. | .. |
|---|
| 2239 | 2256 | */ |
|---|
| 2240 | 2257 | static int __init ns_init_module(void) |
|---|
| 2241 | 2258 | { |
|---|
| 2259 | + struct list_head *pos, *n; |
|---|
| 2242 | 2260 | struct nand_chip *chip; |
|---|
| 2243 | | - struct nandsim *nand; |
|---|
| 2244 | | - int retval = -ENOMEM, i; |
|---|
| 2261 | + struct nandsim *ns; |
|---|
| 2262 | + int ret; |
|---|
| 2245 | 2263 | |
|---|
| 2246 | 2264 | if (bus_width != 8 && bus_width != 16) { |
|---|
| 2247 | 2265 | NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width); |
|---|
| 2248 | 2266 | return -EINVAL; |
|---|
| 2249 | 2267 | } |
|---|
| 2250 | 2268 | |
|---|
| 2251 | | - /* Allocate and initialize mtd_info, nand_chip and nandsim structures */ |
|---|
| 2252 | | - chip = kzalloc(sizeof(struct nand_chip) + sizeof(struct nandsim), |
|---|
| 2253 | | - GFP_KERNEL); |
|---|
| 2254 | | - if (!chip) { |
|---|
| 2269 | + ns = kzalloc(sizeof(struct nandsim), GFP_KERNEL); |
|---|
| 2270 | + if (!ns) { |
|---|
| 2255 | 2271 | NS_ERR("unable to allocate core structures.\n"); |
|---|
| 2256 | 2272 | return -ENOMEM; |
|---|
| 2257 | 2273 | } |
|---|
| 2274 | + chip = &ns->chip; |
|---|
| 2258 | 2275 | nsmtd = nand_to_mtd(chip); |
|---|
| 2259 | | - nand = (struct nandsim *)(chip + 1); |
|---|
| 2260 | | - nand_set_controller_data(chip, (void *)nand); |
|---|
| 2276 | + nand_set_controller_data(chip, (void *)ns); |
|---|
| 2261 | 2277 | |
|---|
| 2262 | | - /* |
|---|
| 2263 | | - * Register simulator's callbacks. |
|---|
| 2264 | | - */ |
|---|
| 2265 | | - chip->cmd_ctrl = ns_hwcontrol; |
|---|
| 2266 | | - chip->read_byte = ns_nand_read_byte; |
|---|
| 2267 | | - chip->dev_ready = ns_device_ready; |
|---|
| 2268 | | - chip->write_buf = ns_nand_write_buf; |
|---|
| 2269 | | - chip->read_buf = ns_nand_read_buf; |
|---|
| 2270 | | - chip->read_word = ns_nand_read_word; |
|---|
| 2271 | | - chip->ecc.mode = NAND_ECC_SOFT; |
|---|
| 2272 | | - chip->ecc.algo = NAND_ECC_HAMMING; |
|---|
| 2273 | 2278 | /* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */ |
|---|
| 2274 | 2279 | /* and 'badblocks' parameters to work */ |
|---|
| 2275 | 2280 | chip->options |= NAND_SKIP_BBTSCAN; |
|---|
| 2276 | 2281 | |
|---|
| 2277 | 2282 | switch (bbt) { |
|---|
| 2278 | 2283 | case 2: |
|---|
| 2279 | | - chip->bbt_options |= NAND_BBT_NO_OOB; |
|---|
| 2284 | + chip->bbt_options |= NAND_BBT_NO_OOB; |
|---|
| 2285 | + fallthrough; |
|---|
| 2280 | 2286 | case 1: |
|---|
| 2281 | | - chip->bbt_options |= NAND_BBT_USE_FLASH; |
|---|
| 2287 | + chip->bbt_options |= NAND_BBT_USE_FLASH; |
|---|
| 2288 | + fallthrough; |
|---|
| 2282 | 2289 | case 0: |
|---|
| 2283 | 2290 | break; |
|---|
| 2284 | 2291 | default: |
|---|
| 2285 | 2292 | NS_ERR("bbt has to be 0..2\n"); |
|---|
| 2286 | | - retval = -EINVAL; |
|---|
| 2287 | | - goto error; |
|---|
| 2293 | + ret = -EINVAL; |
|---|
| 2294 | + goto free_ns_struct; |
|---|
| 2288 | 2295 | } |
|---|
| 2289 | 2296 | /* |
|---|
| 2290 | 2297 | * Perform minimum nandsim structure initialization to handle |
|---|
| 2291 | 2298 | * the initial ID read command correctly |
|---|
| 2292 | 2299 | */ |
|---|
| 2293 | 2300 | if (id_bytes[6] != 0xFF || id_bytes[7] != 0xFF) |
|---|
| 2294 | | - nand->geom.idbytes = 8; |
|---|
| 2301 | + ns->geom.idbytes = 8; |
|---|
| 2295 | 2302 | else if (id_bytes[4] != 0xFF || id_bytes[5] != 0xFF) |
|---|
| 2296 | | - nand->geom.idbytes = 6; |
|---|
| 2303 | + ns->geom.idbytes = 6; |
|---|
| 2297 | 2304 | else if (id_bytes[2] != 0xFF || id_bytes[3] != 0xFF) |
|---|
| 2298 | | - nand->geom.idbytes = 4; |
|---|
| 2305 | + ns->geom.idbytes = 4; |
|---|
| 2299 | 2306 | else |
|---|
| 2300 | | - nand->geom.idbytes = 2; |
|---|
| 2301 | | - nand->regs.status = NS_STATUS_OK(nand); |
|---|
| 2302 | | - nand->nxstate = STATE_UNKNOWN; |
|---|
| 2303 | | - nand->options |= OPT_PAGE512; /* temporary value */ |
|---|
| 2304 | | - memcpy(nand->ids, id_bytes, sizeof(nand->ids)); |
|---|
| 2307 | + ns->geom.idbytes = 2; |
|---|
| 2308 | + ns->regs.status = NS_STATUS_OK(ns); |
|---|
| 2309 | + ns->nxstate = STATE_UNKNOWN; |
|---|
| 2310 | + ns->options |= OPT_PAGE512; /* temporary value */ |
|---|
| 2311 | + memcpy(ns->ids, id_bytes, sizeof(ns->ids)); |
|---|
| 2305 | 2312 | if (bus_width == 16) { |
|---|
| 2306 | | - nand->busw = 16; |
|---|
| 2313 | + ns->busw = 16; |
|---|
| 2307 | 2314 | chip->options |= NAND_BUSWIDTH_16; |
|---|
| 2308 | 2315 | } |
|---|
| 2309 | 2316 | |
|---|
| 2310 | 2317 | nsmtd->owner = THIS_MODULE; |
|---|
| 2311 | 2318 | |
|---|
| 2312 | | - if ((retval = parse_weakblocks()) != 0) |
|---|
| 2313 | | - goto error; |
|---|
| 2319 | + ret = ns_parse_weakblocks(); |
|---|
| 2320 | + if (ret) |
|---|
| 2321 | + goto free_ns_struct; |
|---|
| 2314 | 2322 | |
|---|
| 2315 | | - if ((retval = parse_weakpages()) != 0) |
|---|
| 2316 | | - goto error; |
|---|
| 2323 | + ret = ns_parse_weakpages(); |
|---|
| 2324 | + if (ret) |
|---|
| 2325 | + goto free_wb_list; |
|---|
| 2317 | 2326 | |
|---|
| 2318 | | - if ((retval = parse_gravepages()) != 0) |
|---|
| 2319 | | - goto error; |
|---|
| 2327 | + ret = ns_parse_gravepages(); |
|---|
| 2328 | + if (ret) |
|---|
| 2329 | + goto free_wp_list; |
|---|
| 2320 | 2330 | |
|---|
| 2321 | | - chip->dummy_controller.ops = &ns_controller_ops; |
|---|
| 2322 | | - retval = nand_scan(chip, 1); |
|---|
| 2323 | | - if (retval) { |
|---|
| 2331 | + nand_controller_init(&ns->base); |
|---|
| 2332 | + ns->base.ops = &ns_controller_ops; |
|---|
| 2333 | + chip->controller = &ns->base; |
|---|
| 2334 | + |
|---|
| 2335 | + ret = nand_scan(chip, 1); |
|---|
| 2336 | + if (ret) { |
|---|
| 2324 | 2337 | NS_ERR("Could not scan NAND Simulator device\n"); |
|---|
| 2325 | | - goto error; |
|---|
| 2338 | + goto free_gp_list; |
|---|
| 2326 | 2339 | } |
|---|
| 2327 | 2340 | |
|---|
| 2328 | 2341 | if (overridesize) { |
|---|
| 2329 | 2342 | uint64_t new_size = (uint64_t)nsmtd->erasesize << overridesize; |
|---|
| 2343 | + struct nand_memory_organization *memorg; |
|---|
| 2344 | + u64 targetsize; |
|---|
| 2345 | + |
|---|
| 2346 | + memorg = nanddev_get_memorg(&chip->base); |
|---|
| 2347 | + |
|---|
| 2330 | 2348 | if (new_size >> overridesize != nsmtd->erasesize) { |
|---|
| 2331 | 2349 | NS_ERR("overridesize is too big\n"); |
|---|
| 2332 | | - retval = -EINVAL; |
|---|
| 2333 | | - goto err_exit; |
|---|
| 2350 | + ret = -EINVAL; |
|---|
| 2351 | + goto cleanup_nand; |
|---|
| 2334 | 2352 | } |
|---|
| 2353 | + |
|---|
| 2335 | 2354 | /* N.B. This relies on nand_scan not doing anything with the size before we change it */ |
|---|
| 2336 | 2355 | nsmtd->size = new_size; |
|---|
| 2337 | | - chip->chipsize = new_size; |
|---|
| 2356 | + memorg->eraseblocks_per_lun = 1 << overridesize; |
|---|
| 2357 | + targetsize = nanddev_target_size(&chip->base); |
|---|
| 2338 | 2358 | chip->chip_shift = ffs(nsmtd->erasesize) + overridesize - 1; |
|---|
| 2339 | | - chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; |
|---|
| 2359 | + chip->pagemask = (targetsize >> chip->page_shift) - 1; |
|---|
| 2340 | 2360 | } |
|---|
| 2341 | 2361 | |
|---|
| 2342 | | - if ((retval = setup_wear_reporting(nsmtd)) != 0) |
|---|
| 2343 | | - goto err_exit; |
|---|
| 2362 | + ret = ns_setup_wear_reporting(nsmtd); |
|---|
| 2363 | + if (ret) |
|---|
| 2364 | + goto cleanup_nand; |
|---|
| 2344 | 2365 | |
|---|
| 2345 | | - if ((retval = init_nandsim(nsmtd)) != 0) |
|---|
| 2346 | | - goto err_exit; |
|---|
| 2366 | + ret = ns_init(nsmtd); |
|---|
| 2367 | + if (ret) |
|---|
| 2368 | + goto free_ebw; |
|---|
| 2347 | 2369 | |
|---|
| 2348 | | - if ((retval = nand_create_bbt(chip)) != 0) |
|---|
| 2349 | | - goto err_exit; |
|---|
| 2370 | + ret = nand_create_bbt(chip); |
|---|
| 2371 | + if (ret) |
|---|
| 2372 | + goto free_ns_object; |
|---|
| 2350 | 2373 | |
|---|
| 2351 | | - if ((retval = parse_badblocks(nand, nsmtd)) != 0) |
|---|
| 2352 | | - goto err_exit; |
|---|
| 2374 | + ret = ns_parse_badblocks(ns, nsmtd); |
|---|
| 2375 | + if (ret) |
|---|
| 2376 | + goto free_ns_object; |
|---|
| 2353 | 2377 | |
|---|
| 2354 | 2378 | /* Register NAND partitions */ |
|---|
| 2355 | | - retval = mtd_device_register(nsmtd, &nand->partitions[0], |
|---|
| 2356 | | - nand->nbparts); |
|---|
| 2357 | | - if (retval != 0) |
|---|
| 2358 | | - goto err_exit; |
|---|
| 2379 | + ret = mtd_device_register(nsmtd, &ns->partitions[0], ns->nbparts); |
|---|
| 2380 | + if (ret) |
|---|
| 2381 | + goto free_ns_object; |
|---|
| 2359 | 2382 | |
|---|
| 2360 | | - if ((retval = nandsim_debugfs_create(nand)) != 0) |
|---|
| 2361 | | - goto err_exit; |
|---|
| 2383 | + ret = ns_debugfs_create(ns); |
|---|
| 2384 | + if (ret) |
|---|
| 2385 | + goto unregister_mtd; |
|---|
| 2362 | 2386 | |
|---|
| 2363 | 2387 | return 0; |
|---|
| 2364 | 2388 | |
|---|
| 2365 | | -err_exit: |
|---|
| 2366 | | - free_nandsim(nand); |
|---|
| 2367 | | - nand_release(chip); |
|---|
| 2368 | | - for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i) |
|---|
| 2369 | | - kfree(nand->partitions[i].name); |
|---|
| 2370 | | -error: |
|---|
| 2371 | | - kfree(chip); |
|---|
| 2372 | | - free_lists(); |
|---|
| 2389 | +unregister_mtd: |
|---|
| 2390 | + WARN_ON(mtd_device_unregister(nsmtd)); |
|---|
| 2391 | +free_ns_object: |
|---|
| 2392 | + ns_free(ns); |
|---|
| 2393 | +free_ebw: |
|---|
| 2394 | + kfree(erase_block_wear); |
|---|
| 2395 | +cleanup_nand: |
|---|
| 2396 | + nand_cleanup(chip); |
|---|
| 2397 | +free_gp_list: |
|---|
| 2398 | + list_for_each_safe(pos, n, &grave_pages) { |
|---|
| 2399 | + list_del(pos); |
|---|
| 2400 | + kfree(list_entry(pos, struct grave_page, list)); |
|---|
| 2401 | + } |
|---|
| 2402 | +free_wp_list: |
|---|
| 2403 | + list_for_each_safe(pos, n, &weak_pages) { |
|---|
| 2404 | + list_del(pos); |
|---|
| 2405 | + kfree(list_entry(pos, struct weak_page, list)); |
|---|
| 2406 | + } |
|---|
| 2407 | +free_wb_list: |
|---|
| 2408 | + list_for_each_safe(pos, n, &weak_blocks) { |
|---|
| 2409 | + list_del(pos); |
|---|
| 2410 | + kfree(list_entry(pos, struct weak_block, list)); |
|---|
| 2411 | + } |
|---|
| 2412 | +free_ns_struct: |
|---|
| 2413 | + kfree(ns); |
|---|
| 2373 | 2414 | |
|---|
| 2374 | | - return retval; |
|---|
| 2415 | + return ret; |
|---|
| 2375 | 2416 | } |
|---|
| 2376 | 2417 | |
|---|
| 2377 | 2418 | module_init(ns_init_module); |
|---|
| .. | .. |
|---|
| 2383 | 2424 | { |
|---|
| 2384 | 2425 | struct nand_chip *chip = mtd_to_nand(nsmtd); |
|---|
| 2385 | 2426 | struct nandsim *ns = nand_get_controller_data(chip); |
|---|
| 2386 | | - int i; |
|---|
| 2427 | + struct list_head *pos, *n; |
|---|
| 2387 | 2428 | |
|---|
| 2388 | | - free_nandsim(ns); /* Free nandsim private resources */ |
|---|
| 2389 | | - nand_release(chip); /* Unregister driver */ |
|---|
| 2390 | | - for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i) |
|---|
| 2391 | | - kfree(ns->partitions[i].name); |
|---|
| 2392 | | - kfree(mtd_to_nand(nsmtd)); /* Free other structures */ |
|---|
| 2393 | | - free_lists(); |
|---|
| 2429 | + ns_debugfs_remove(ns); |
|---|
| 2430 | + WARN_ON(mtd_device_unregister(nsmtd)); |
|---|
| 2431 | + ns_free(ns); |
|---|
| 2432 | + kfree(erase_block_wear); |
|---|
| 2433 | + nand_cleanup(chip); |
|---|
| 2434 | + |
|---|
| 2435 | + list_for_each_safe(pos, n, &grave_pages) { |
|---|
| 2436 | + list_del(pos); |
|---|
| 2437 | + kfree(list_entry(pos, struct grave_page, list)); |
|---|
| 2438 | + } |
|---|
| 2439 | + |
|---|
| 2440 | + list_for_each_safe(pos, n, &weak_pages) { |
|---|
| 2441 | + list_del(pos); |
|---|
| 2442 | + kfree(list_entry(pos, struct weak_page, list)); |
|---|
| 2443 | + } |
|---|
| 2444 | + |
|---|
| 2445 | + list_for_each_safe(pos, n, &weak_blocks) { |
|---|
| 2446 | + list_del(pos); |
|---|
| 2447 | + kfree(list_entry(pos, struct weak_block, list)); |
|---|
| 2448 | + } |
|---|
| 2449 | + |
|---|
| 2450 | + kfree(ns); |
|---|
| 2394 | 2451 | } |
|---|
| 2395 | 2452 | |
|---|
| 2396 | 2453 | module_exit(ns_cleanup_module); |
|---|
| 2397 | 2454 | |
|---|
| 2398 | 2455 | MODULE_LICENSE ("GPL"); |
|---|
| 2456 | +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); |
|---|
| 2399 | 2457 | MODULE_AUTHOR ("Artem B. Bityuckiy"); |
|---|
| 2400 | 2458 | MODULE_DESCRIPTION ("The NAND flash simulator"); |
|---|