Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
linux
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
2
Pull requests
0
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
808373f
Documentation
arch
block
certs
crypto
drivers
accessibility
acpi
amba
android
ata
atm
auxdisplay
base
bcma
block
bluetooth
bus
cdrom
char
clk
clocksource
connector
cpufreq
cpuidle
crypto
dax
dca
devfreq
dio
dma-buf
dma
edac
eisa
extcon
firewire
firmware
fmc
fpga
fsi
gpio
gpu
hid
hsi
hv
hwmon
hwspinlock
hwtracing
i2c
ide
idle
iio
infiniband
input
iommu
ipack
irqchip
isdn
leds
lightnvm
macintosh
mailbox
mcb
md
media
memory
memstick
message
mfd
misc
mmc
mtd
chips
devices
lpddr
maps
nand
atmel
bcm47xxnflash
brcmnand
gpmi-nand
Kconfig
Makefile
ams-delta.c
au1550nd.c
bf5xx_nand.c
cafe_nand.c
cmx270_nand.c
cs553x_nand.c
davinci_nand.c
denali.c
denali.h
denali_dt.c
denali_pci.c
diskonchip.c
docg4.c
fsl_elbc_nand.c
fsl_ifc_nand.c
fsl_upm.c
fsmc_nand.c
gpio.c
hisi504_nand.c
jz4740_nand.c
jz4780_bch.c
jz4780_bch.h
jz4780_nand.c
lpc32xx_mlc.c
lpc32xx_slc.c
mpc5121_nfc.c
mtk_ecc.c
mtk_ecc.h
mtk_nand.c
mxc_nand.c
nand_amd.c
nand_base.c
nand_bbt.c
nand_bch.c
nand_ecc.c
nand_hynix.c
nand_ids.c
nand_macronix.c
nand_micron.c
nand_samsung.c
nand_timings.c
nand_toshiba.c
nandsim.c
ndfc.c
nuc900_nand.c
omap2.c
omap_elm.c
orion_nand.c
oxnas_nand.c
pasemi_nand.c
plat_nand.c
pxa3xx_nand.c
qcom_nandc.c
r852.c
r852.h
s3c2410.c
sh_flctl.c
sharpsl.c
sm_common.c
sm_common.h
socrates_nand.c
sunxi_nand.c
tango_nand.c
tmio_nand.c
txx9ndfmc.c
vf610_nfc.c
xway_nand.c
onenand
parsers
spi-nor
tests
ubi
Kconfig
Makefile
afs.c
ar7part.c
bcm47xxpart.c
bcm63xxpart.c
cmdlinepart.c
ftl.c
inftlcore.c
inftlmount.c
mtd_blkdevs.c
mtdblock.c
mtdblock_ro.c
mtdchar.c
mtdconcat.c
mtdcore.c
mtdcore.h
mtdoops.c
mtdpart.c
mtdsuper.c
mtdswap.c
nftlcore.c
nftlmount.c
ofpart.c
redboot.c
rfd_ftl.c
sm_ftl.c
sm_ftl.h
ssfdc.c
mux
net
nfc
ntb
nubus
nvdimm
nvme
nvmem
of
oprofile
parisc
parport
pci
pcmcia
perf
phy
pinctrl
platform
pnp
power
powercap
pps
ps3
ptp
pwm
rapidio
ras
regulator
remoteproc
reset
rpmsg
rtc
s390
sbus
scsi
sfi
sh
sn
soc
spi
spmi
ssb
staging
target
tc
tee
thermal
thunderbolt
tty
uio
usb
uwb
vfio
vhost
video
virt
virtio
vlynq
vme
w1
watchdog
xen
zorro
Kconfig
Makefile
firmware
fs
include
init
ipc
kernel
lib
mm
net
samples
scripts
security
sound
tools
usr
virt
.cocciconfig
.get_maintainer.ignore
.gitattributes
.gitignore
.mailmap
COPYING
CREDITS
Kbuild
Kconfig
MAINTAINERS
Makefile
README
Breadcrumbs
linux
/
drivers
/
mtd
/
nand
/
omap_elm.c
Copy path
Blame
Blame
Latest commit
History
History
579 lines (505 loc) · 15.9 KB
Breadcrumbs
linux
/
drivers
/
mtd
/
nand
/
omap_elm.c
Top
File metadata and controls
Code
Blame
579 lines (505 loc) · 15.9 KB
Raw
/* * Error Location Module * * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #define DRIVER_NAME "omap-elm" #include <linux/platform_device.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/of.h> #include <linux/sched.h> #include <linux/pm_runtime.h> #include <linux/platform_data/elm.h> #define ELM_SYSCONFIG 0x010 #define ELM_IRQSTATUS 0x018 #define ELM_IRQENABLE 0x01c #define ELM_LOCATION_CONFIG 0x020 #define ELM_PAGE_CTRL 0x080 #define ELM_SYNDROME_FRAGMENT_0 0x400 #define ELM_SYNDROME_FRAGMENT_1 0x404 #define ELM_SYNDROME_FRAGMENT_2 0x408 #define ELM_SYNDROME_FRAGMENT_3 0x40c #define ELM_SYNDROME_FRAGMENT_4 0x410 #define ELM_SYNDROME_FRAGMENT_5 0x414 #define ELM_SYNDROME_FRAGMENT_6 0x418 #define ELM_LOCATION_STATUS 0x800 #define ELM_ERROR_LOCATION_0 0x880 /* ELM Interrupt Status Register */ #define INTR_STATUS_PAGE_VALID BIT(8) /* ELM Interrupt Enable Register */ #define INTR_EN_PAGE_MASK BIT(8) /* ELM Location Configuration Register */ #define ECC_BCH_LEVEL_MASK 0x3 /* ELM syndrome */ #define ELM_SYNDROME_VALID BIT(16) /* ELM_LOCATION_STATUS Register */ #define ECC_CORRECTABLE_MASK BIT(8) #define ECC_NB_ERRORS_MASK 0x1f /* ELM_ERROR_LOCATION_0-15 Registers */ #define ECC_ERROR_LOCATION_MASK 0x1fff #define ELM_ECC_SIZE 0x7ff #define SYNDROME_FRAGMENT_REG_SIZE 0x40 #define ERROR_LOCATION_SIZE 0x100 struct elm_registers { u32 elm_irqenable; u32 elm_sysconfig; u32 elm_location_config; u32 elm_page_ctrl; u32 elm_syndrome_fragment_6[ERROR_VECTOR_MAX]; u32 elm_syndrome_fragment_5[ERROR_VECTOR_MAX]; u32 elm_syndrome_fragment_4[ERROR_VECTOR_MAX]; u32 elm_syndrome_fragment_3[ERROR_VECTOR_MAX]; u32 elm_syndrome_fragment_2[ERROR_VECTOR_MAX]; u32 elm_syndrome_fragment_1[ERROR_VECTOR_MAX]; u32 elm_syndrome_fragment_0[ERROR_VECTOR_MAX]; }; struct elm_info { struct device *dev; void __iomem *elm_base; struct completion elm_completion; struct list_head list; enum bch_ecc bch_type; struct elm_registers elm_regs; int ecc_steps; int ecc_syndrome_size; }; static LIST_HEAD(elm_devices); static void elm_write_reg(struct elm_info *info, int offset, u32 val) { writel(val, info->elm_base + offset); } static u32 elm_read_reg(struct elm_info *info, int offset) { return readl(info->elm_base + offset); } /** * elm_config - Configure ELM module * @dev: ELM device * @bch_type: Type of BCH ecc */ int elm_config(struct device *dev, enum bch_ecc bch_type, int ecc_steps, int ecc_step_size, int ecc_syndrome_size) { u32 reg_val; struct elm_info *info = dev_get_drvdata(dev); if (!info) { dev_err(dev, "Unable to configure elm - device not probed?\n"); return -EPROBE_DEFER; } /* ELM cannot detect ECC errors for chunks > 1KB */ if (ecc_step_size > ((ELM_ECC_SIZE + 1) / 2)) { dev_err(dev, "unsupported config ecc-size=%d\n", ecc_step_size); return -EINVAL; } /* ELM support 8 error syndrome process */ if (ecc_steps > ERROR_VECTOR_MAX) { dev_err(dev, "unsupported config ecc-step=%d\n", ecc_steps); return -EINVAL; } reg_val = (bch_type & ECC_BCH_LEVEL_MASK) | (ELM_ECC_SIZE << 16); elm_write_reg(info, ELM_LOCATION_CONFIG, reg_val); info->bch_type = bch_type; info->ecc_steps = ecc_steps; info->ecc_syndrome_size = ecc_syndrome_size; return 0; } EXPORT_SYMBOL(elm_config); /** * elm_configure_page_mode - Enable/Disable page mode * @info: elm info * @index: index number of syndrome fragment vector * @enable: enable/disable flag for page mode * * Enable page mode for syndrome fragment index */ static void elm_configure_page_mode(struct elm_info *info, int index, bool enable) { u32 reg_val; reg_val = elm_read_reg(info, ELM_PAGE_CTRL); if (enable) reg_val |= BIT(index); /* enable page mode */ else reg_val &= ~BIT(index); /* disable page mode */ elm_write_reg(info, ELM_PAGE_CTRL, reg_val); } /** * elm_load_syndrome - Load ELM syndrome reg * @info: elm info * @err_vec: elm error vectors * @ecc: buffer with calculated ecc * * Load syndrome fragment registers with calculated ecc in reverse order. */ static void elm_load_syndrome(struct elm_info *info, struct elm_errorvec *err_vec, u8 *ecc) { int i, offset; u32 val; for (i = 0; i < info->ecc_steps; i++) { /* Check error reported */ if (err_vec[i].error_reported) { elm_configure_page_mode(info, i, true); offset = ELM_SYNDROME_FRAGMENT_0 + SYNDROME_FRAGMENT_REG_SIZE * i; switch (info->bch_type) { case BCH8_ECC: /* syndrome fragment 0 = ecc[9-12B] */ val = (__force u32)cpu_to_be32(*(u32 *)&ecc[9]); elm_write_reg(info, offset, val); /* syndrome fragment 1 = ecc[5-8B] */ offset += 4; val = (__force u32)cpu_to_be32(*(u32 *)&ecc[5]); elm_write_reg(info, offset, val); /* syndrome fragment 2 = ecc[1-4B] */ offset += 4; val = (__force u32)cpu_to_be32(*(u32 *)&ecc[1]); elm_write_reg(info, offset, val); /* syndrome fragment 3 = ecc[0B] */ offset += 4; val = ecc[0]; elm_write_reg(info, offset, val); break; case BCH4_ECC: /* syndrome fragment 0 = ecc[20-52b] bits */ val = ((__force u32)cpu_to_be32(*(u32 *)&ecc[3]) >> 4) | ((ecc[2] & 0xf) << 28); elm_write_reg(info, offset, val); /* syndrome fragment 1 = ecc[0-20b] bits */ offset += 4; val = (__force u32)cpu_to_be32(*(u32 *)&ecc[0]) >> 12; elm_write_reg(info, offset, val); break; case BCH16_ECC: val = (__force u32)cpu_to_be32(*(u32 *)&ecc[22]); elm_write_reg(info, offset, val); offset += 4; val = (__force u32)cpu_to_be32(*(u32 *)&ecc[18]); elm_write_reg(info, offset, val); offset += 4; val = (__force u32)cpu_to_be32(*(u32 *)&ecc[14]); elm_write_reg(info, offset, val); offset += 4; val = (__force u32)cpu_to_be32(*(u32 *)&ecc[10]); elm_write_reg(info, offset, val); offset += 4; val = (__force u32)cpu_to_be32(*(u32 *)&ecc[6]); elm_write_reg(info, offset, val); offset += 4; val = (__force u32)cpu_to_be32(*(u32 *)&ecc[2]); elm_write_reg(info, offset, val); offset += 4; val = (__force u32)cpu_to_be32(*(u32 *)&ecc[0]) >> 16; elm_write_reg(info, offset, val); break; default: pr_err("invalid config bch_type\n"); } } /* Update ecc pointer with ecc byte size */ ecc += info->ecc_syndrome_size; } } /** * elm_start_processing - start elm syndrome processing * @info: elm info * @err_vec: elm error vectors * * Set syndrome valid bit for syndrome fragment registers for which * elm syndrome fragment registers are loaded. This enables elm module * to start processing syndrome vectors. */ static void elm_start_processing(struct elm_info *info, struct elm_errorvec *err_vec) { int i, offset; u32 reg_val; /* * Set syndrome vector valid, so that ELM module * will process it for vectors error is reported */ for (i = 0; i < info->ecc_steps; i++) { if (err_vec[i].error_reported) { offset = ELM_SYNDROME_FRAGMENT_6 + SYNDROME_FRAGMENT_REG_SIZE * i; reg_val = elm_read_reg(info, offset); reg_val |= ELM_SYNDROME_VALID; elm_write_reg(info, offset, reg_val); } } } /** * elm_error_correction - locate correctable error position * @info: elm info * @err_vec: elm error vectors * * On completion of processing by elm module, error location status * register updated with correctable/uncorrectable error information. * In case of correctable errors, number of errors located from * elm location status register & read the positions from * elm error location register. */ static void elm_error_correction(struct elm_info *info, struct elm_errorvec *err_vec) { int i, j, errors = 0; int offset; u32 reg_val; for (i = 0; i < info->ecc_steps; i++) { /* Check error reported */ if (err_vec[i].error_reported) { offset = ELM_LOCATION_STATUS + ERROR_LOCATION_SIZE * i; reg_val = elm_read_reg(info, offset); /* Check correctable error or not */ if (reg_val & ECC_CORRECTABLE_MASK) { offset = ELM_ERROR_LOCATION_0 + ERROR_LOCATION_SIZE * i; /* Read count of correctable errors */ err_vec[i].error_count = reg_val & ECC_NB_ERRORS_MASK; /* Update the error locations in error vector */ for (j = 0; j < err_vec[i].error_count; j++) { reg_val = elm_read_reg(info, offset); err_vec[i].error_loc[j] = reg_val & ECC_ERROR_LOCATION_MASK; /* Update error location register */ offset += 4; } errors += err_vec[i].error_count; } else { err_vec[i].error_uncorrectable = true; } /* Clearing interrupts for processed error vectors */ elm_write_reg(info, ELM_IRQSTATUS, BIT(i)); /* Disable page mode */ elm_configure_page_mode(info, i, false); } } } /** * elm_decode_bch_error_page - Locate error position * @dev: device pointer * @ecc_calc: calculated ECC bytes from GPMC * @err_vec: elm error vectors * * Called with one or more error reported vectors & vectors with * error reported is updated in err_vec[].error_reported */ void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, struct elm_errorvec *err_vec) { struct elm_info *info = dev_get_drvdata(dev); u32 reg_val; /* Enable page mode interrupt */ reg_val = elm_read_reg(info, ELM_IRQSTATUS); elm_write_reg(info, ELM_IRQSTATUS, reg_val & INTR_STATUS_PAGE_VALID); elm_write_reg(info, ELM_IRQENABLE, INTR_EN_PAGE_MASK); /* Load valid ecc byte to syndrome fragment register */ elm_load_syndrome(info, err_vec, ecc_calc); /* Enable syndrome processing for which syndrome fragment is updated */ elm_start_processing(info, err_vec); /* Wait for ELM module to finish locating error correction */ wait_for_completion(&info->elm_completion); /* Disable page mode interrupt */ reg_val = elm_read_reg(info, ELM_IRQENABLE); elm_write_reg(info, ELM_IRQENABLE, reg_val & ~INTR_EN_PAGE_MASK); elm_error_correction(info, err_vec); } EXPORT_SYMBOL(elm_decode_bch_error_page); static irqreturn_t elm_isr(int this_irq, void *dev_id) { u32 reg_val; struct elm_info *info = dev_id; reg_val = elm_read_reg(info, ELM_IRQSTATUS); /* All error vectors processed */ if (reg_val & INTR_STATUS_PAGE_VALID) { elm_write_reg(info, ELM_IRQSTATUS, reg_val & INTR_STATUS_PAGE_VALID); complete(&info->elm_completion); return IRQ_HANDLED; } return IRQ_NONE; } static int elm_probe(struct platform_device *pdev) { int ret = 0; struct resource *res, *irq; struct elm_info *info; info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; info->dev = &pdev->dev; irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!irq) { dev_err(&pdev->dev, "no irq resource defined\n"); return -ENODEV; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); info->elm_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(info->elm_base)) return PTR_ERR(info->elm_base); ret = devm_request_irq(&pdev->dev, irq->start, elm_isr, 0, pdev->name, info); if (ret) { dev_err(&pdev->dev, "failure requesting %pr\n", irq); return ret; } pm_runtime_enable(&pdev->dev); if (pm_runtime_get_sync(&pdev->dev) < 0) { ret = -EINVAL; pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); dev_err(&pdev->dev, "can't enable clock\n"); return ret; } init_completion(&info->elm_completion); INIT_LIST_HEAD(&info->list); list_add(&info->list, &elm_devices); platform_set_drvdata(pdev, info); return ret; } static int elm_remove(struct platform_device *pdev) { pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); return 0; } #ifdef CONFIG_PM_SLEEP /** * elm_context_save * saves ELM configurations to preserve them across Hardware powered-down */ static int elm_context_save(struct elm_info *info) { struct elm_registers *regs = &info->elm_regs; enum bch_ecc bch_type = info->bch_type; u32 offset = 0, i; regs->elm_irqenable = elm_read_reg(info, ELM_IRQENABLE); regs->elm_sysconfig = elm_read_reg(info, ELM_SYSCONFIG); regs->elm_location_config = elm_read_reg(info, ELM_LOCATION_CONFIG); regs->elm_page_ctrl = elm_read_reg(info, ELM_PAGE_CTRL); for (i = 0; i < ERROR_VECTOR_MAX; i++) { offset = i * SYNDROME_FRAGMENT_REG_SIZE; switch (bch_type) { case BCH16_ECC: regs->elm_syndrome_fragment_6[i] = elm_read_reg(info, ELM_SYNDROME_FRAGMENT_6 + offset); regs->elm_syndrome_fragment_5[i] = elm_read_reg(info, ELM_SYNDROME_FRAGMENT_5 + offset); regs->elm_syndrome_fragment_4[i] = elm_read_reg(info, ELM_SYNDROME_FRAGMENT_4 + offset); case BCH8_ECC: regs->elm_syndrome_fragment_3[i] = elm_read_reg(info, ELM_SYNDROME_FRAGMENT_3 + offset); regs->elm_syndrome_fragment_2[i] = elm_read_reg(info, ELM_SYNDROME_FRAGMENT_2 + offset); case BCH4_ECC: regs->elm_syndrome_fragment_1[i] = elm_read_reg(info, ELM_SYNDROME_FRAGMENT_1 + offset); regs->elm_syndrome_fragment_0[i] = elm_read_reg(info, ELM_SYNDROME_FRAGMENT_0 + offset); break; default: return -EINVAL; } /* ELM SYNDROME_VALID bit in SYNDROME_FRAGMENT_6[] needs * to be saved for all BCH schemes*/ regs->elm_syndrome_fragment_6[i] = elm_read_reg(info, ELM_SYNDROME_FRAGMENT_6 + offset); } return 0; } /** * elm_context_restore * writes configurations saved duing power-down back into ELM registers */ static int elm_context_restore(struct elm_info *info) { struct elm_registers *regs = &info->elm_regs; enum bch_ecc bch_type = info->bch_type; u32 offset = 0, i; elm_write_reg(info, ELM_IRQENABLE, regs->elm_irqenable); elm_write_reg(info, ELM_SYSCONFIG, regs->elm_sysconfig); elm_write_reg(info, ELM_LOCATION_CONFIG, regs->elm_location_config); elm_write_reg(info, ELM_PAGE_CTRL, regs->elm_page_ctrl); for (i = 0; i < ERROR_VECTOR_MAX; i++) { offset = i * SYNDROME_FRAGMENT_REG_SIZE; switch (bch_type) { case BCH16_ECC: elm_write_reg(info, ELM_SYNDROME_FRAGMENT_6 + offset, regs->elm_syndrome_fragment_6[i]); elm_write_reg(info, ELM_SYNDROME_FRAGMENT_5 + offset, regs->elm_syndrome_fragment_5[i]); elm_write_reg(info, ELM_SYNDROME_FRAGMENT_4 + offset, regs->elm_syndrome_fragment_4[i]); case BCH8_ECC: elm_write_reg(info, ELM_SYNDROME_FRAGMENT_3 + offset, regs->elm_syndrome_fragment_3[i]); elm_write_reg(info, ELM_SYNDROME_FRAGMENT_2 + offset, regs->elm_syndrome_fragment_2[i]); case BCH4_ECC: elm_write_reg(info, ELM_SYNDROME_FRAGMENT_1 + offset, regs->elm_syndrome_fragment_1[i]); elm_write_reg(info, ELM_SYNDROME_FRAGMENT_0 + offset, regs->elm_syndrome_fragment_0[i]); break; default: return -EINVAL; } /* ELM_SYNDROME_VALID bit to be set in last to trigger FSM */ elm_write_reg(info, ELM_SYNDROME_FRAGMENT_6 + offset, regs->elm_syndrome_fragment_6[i] & ELM_SYNDROME_VALID); } return 0; } static int elm_suspend(struct device *dev) { struct elm_info *info = dev_get_drvdata(dev); elm_context_save(info); pm_runtime_put_sync(dev); return 0; } static int elm_resume(struct device *dev) { struct elm_info *info = dev_get_drvdata(dev); pm_runtime_get_sync(dev); elm_context_restore(info); return 0; } #endif static SIMPLE_DEV_PM_OPS(elm_pm_ops, elm_suspend, elm_resume); #ifdef CONFIG_OF static const struct of_device_id elm_of_match[] = { { .compatible = "ti,am3352-elm" }, {}, }; MODULE_DEVICE_TABLE(of, elm_of_match); #endif static struct platform_driver elm_driver = { .driver = { .name = DRIVER_NAME, .of_match_table = of_match_ptr(elm_of_match), .pm = &elm_pm_ops, }, .probe = elm_probe, .remove = elm_remove, }; module_platform_driver(elm_driver); MODULE_DESCRIPTION("ELM driver for BCH error correction"); MODULE_AUTHOR("Texas Instruments"); MODULE_ALIAS("platform:" DRIVER_NAME); MODULE_LICENSE("GPL v2");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
You can’t perform that action at this time.