summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWolfgang Denk <wd@denx.de>2009-03-21 22:15:49 +0100
committerWolfgang Denk <wd@denx.de>2009-03-21 22:15:49 +0100
commitee1702d75a30d076139d1841383a1fa7220a0e11 (patch)
treeb008c231b7d5e4e52ac49aec9a49bc73413aaf30
parente60beb13cf0135dc71c541021487b5ccc4d269cb (diff)
parentfaac4fd852e39cb1d7a740801b060e41aeacef1f (diff)
downloadu-boot-imx-ee1702d75a30d076139d1841383a1fa7220a0e11.zip
u-boot-imx-ee1702d75a30d076139d1841383a1fa7220a0e11.tar.gz
u-boot-imx-ee1702d75a30d076139d1841383a1fa7220a0e11.tar.bz2
Merge branch 'next' of ../next
-rwxr-xr-xMAKEALL1
-rw-r--r--Makefile20
-rw-r--r--README1
-rw-r--r--board/AtmarkTechno/suzaku/u-boot.lds2
-rw-r--r--board/BuS/EB+MCF-EV123/u-boot.lds3
-rw-r--r--board/LEOX/elpt860/u-boot.lds4
-rw-r--r--board/MAI/AmigaOneG3SE/enet.c42
-rw-r--r--board/MAI/AmigaOneG3SE/u-boot.lds4
-rw-r--r--board/Marvell/db64360/u-boot.lds4
-rw-r--r--board/Marvell/db64460/u-boot.lds4
-rw-r--r--board/RPXClassic/RPXClassic.c16
-rw-r--r--board/RPXClassic/u-boot.lds4
-rw-r--r--board/RPXlite/u-boot.lds4
-rw-r--r--board/RPXlite_dw/u-boot.lds4
-rw-r--r--board/RRvision/u-boot.lds4
-rw-r--r--board/actux1/u-boot.lds2
-rw-r--r--board/actux2/u-boot.lds2
-rw-r--r--board/actux3/u-boot.lds2
-rw-r--r--board/actux4/u-boot.lds2
-rw-r--r--board/adder/u-boot.lds4
-rw-r--r--board/ads5121/u-boot.lds4
-rw-r--r--board/altera/dk1c20/u-boot.lds2
-rw-r--r--board/altera/dk1s10/u-boot.lds2
-rw-r--r--board/altera/ep1c20/u-boot.lds3
-rw-r--r--board/altera/ep1s10/u-boot.lds3
-rw-r--r--board/altera/ep1s40/u-boot.lds3
-rw-r--r--board/amcc/acadia/u-boot-nand.lds4
-rw-r--r--board/amcc/acadia/u-boot.lds4
-rw-r--r--board/amcc/bamboo/u-boot-nand.lds4
-rw-r--r--board/amcc/bamboo/u-boot.lds4
-rw-r--r--board/amcc/bubinga/u-boot.lds4
-rw-r--r--board/amcc/canyonlands/u-boot-nand.lds4
-rw-r--r--board/amcc/canyonlands/u-boot.lds4
-rw-r--r--board/amcc/ebony/u-boot.lds4
-rw-r--r--board/amcc/katmai/u-boot.lds4
-rw-r--r--board/amcc/kilauea/u-boot-nand.lds4
-rw-r--r--board/amcc/kilauea/u-boot.lds4
-rw-r--r--board/amcc/luan/u-boot.lds4
-rw-r--r--board/amcc/makalu/u-boot.lds4
-rw-r--r--board/amcc/ocotea/u-boot.lds4
-rw-r--r--board/amcc/redwood/u-boot.lds4
-rw-r--r--board/amcc/sequoia/u-boot-nand.lds4
-rw-r--r--board/amcc/sequoia/u-boot.lds4
-rw-r--r--board/amcc/taihu/u-boot.lds4
-rw-r--r--board/amcc/taishan/u-boot.lds4
-rw-r--r--board/amcc/walnut/u-boot.lds4
-rw-r--r--board/amcc/yosemite/u-boot.lds4
-rw-r--r--board/amcc/yucca/u-boot.lds4
-rw-r--r--board/amirix/ap1000/u-boot.lds4
-rw-r--r--board/apollon/u-boot.lds2
-rw-r--r--board/armadillo/u-boot.lds2
-rw-r--r--board/armltd/versatile/u-boot.lds2
-rw-r--r--board/assabet/u-boot.lds2
-rw-r--r--board/atmel/at91rm9200dk/u-boot.lds2
-rw-r--r--board/atmel/atngw100/u-boot.lds3
-rw-r--r--board/atmel/atstk1000/u-boot.lds3
-rw-r--r--board/atum8548/u-boot.lds4
-rw-r--r--board/c2mon/u-boot.lds4
-rw-r--r--board/cerf250/u-boot.lds2
-rw-r--r--board/cm4008/u-boot.lds2
-rw-r--r--board/cm41xx/u-boot.lds2
-rw-r--r--board/cm5200/u-boot.lds4
-rw-r--r--board/cmc_pu2/load_sernum_ethaddr.c18
-rw-r--r--board/cmc_pu2/u-boot.lds2
-rw-r--r--board/cobra5272/u-boot.lds3
-rw-r--r--board/cogent/u-boot.lds4
-rw-r--r--board/cradle/u-boot.lds2
-rw-r--r--board/cray/L1/u-boot.lds4
-rw-r--r--board/csb226/u-boot.lds2
-rw-r--r--board/csb272/u-boot.lds4
-rw-r--r--board/csb472/u-boot.lds4
-rw-r--r--board/csb637/u-boot.lds2
-rw-r--r--board/dave/B2/u-boot.lds2
-rw-r--r--board/dave/PPChameleonEVB/u-boot.lds4
-rw-r--r--board/davinci/dvevm/u-boot.lds2
-rw-r--r--board/davinci/schmoogie/u-boot.lds2
-rw-r--r--board/davinci/sffsdr/u-boot.lds2
-rw-r--r--board/davinci/sonata/u-boot.lds2
-rw-r--r--board/dbau1x00/u-boot.lds2
-rw-r--r--board/delta/u-boot.lds2
-rw-r--r--board/digsy_mtc/Makefile32
-rw-r--r--board/digsy_mtc/config.mk24
-rw-r--r--board/digsy_mtc/digsy_mtc.c307
-rw-r--r--board/digsy_mtc/eeprom.h32
-rw-r--r--board/digsy_mtc/is42s16800a-7t.h28
-rw-r--r--board/dnp1110/u-boot.lds2
-rw-r--r--board/eNET/u-boot.lds2
-rw-r--r--board/earthlcd/favr-32-ezkit/u-boot.lds3
-rw-r--r--board/eltec/bab7xx/u-boot.lds4
-rw-r--r--board/eltec/elppc/u-boot.lds4
-rw-r--r--board/eltec/mhpc/u-boot.lds4
-rw-r--r--board/emk/top860/u-boot.lds4
-rw-r--r--board/ep7312/u-boot.lds2
-rw-r--r--board/ep88x/u-boot.lds4
-rw-r--r--board/eric/u-boot.lds4
-rw-r--r--board/esd/adciop/u-boot.lds8
-rw-r--r--board/esd/apc405/apc405.c2
-rw-r--r--board/esd/apc405/u-boot.lds19
-rw-r--r--board/esd/ar405/ar405.c83
-rw-r--r--board/esd/ar405/u-boot.lds32
-rw-r--r--board/esd/ash405/ash405.c12
-rw-r--r--board/esd/ash405/u-boot.lds19
-rw-r--r--board/esd/canbt/canbt.c7
-rw-r--r--board/esd/canbt/u-boot.lds30
-rw-r--r--board/esd/cms700/cms700.c13
-rw-r--r--board/esd/cms700/u-boot.lds19
-rw-r--r--board/esd/common/fpga.c14
-rw-r--r--board/esd/common/lcd.h14
-rw-r--r--board/esd/common/xilinx_jtag/ports.c5
-rw-r--r--board/esd/cpci2dp/cpci2dp.c18
-rw-r--r--board/esd/cpci2dp/u-boot.lds19
-rw-r--r--board/esd/cpci405/cpci405.c8
-rw-r--r--board/esd/cpci405/u-boot.lds4
-rw-r--r--board/esd/cpci750/u-boot.lds4
-rw-r--r--board/esd/cpciiser4/cpciiser4.c3
-rw-r--r--board/esd/cpciiser4/u-boot.lds19
-rw-r--r--board/esd/dasa_sim/cmd_dasa_sim.c9
-rw-r--r--board/esd/dasa_sim/config.mk11
-rw-r--r--board/esd/dasa_sim/dasa_sim.c12
-rw-r--r--board/esd/dasa_sim/eeprom.c18
-rw-r--r--board/esd/dasa_sim/u-boot.lds30
-rw-r--r--board/esd/dp405/dp405.c14
-rw-r--r--board/esd/dp405/u-boot.lds20
-rw-r--r--board/esd/du405/du405.c14
-rw-r--r--board/esd/du405/u-boot.lds19
-rw-r--r--board/esd/du440/du440.c13
-rw-r--r--board/esd/du440/u-boot.lds7
-rw-r--r--board/esd/hh405/hh405.c166
-rw-r--r--board/esd/hh405/u-boot.lds19
-rw-r--r--board/esd/hub405/hub405.c56
-rw-r--r--board/esd/hub405/u-boot.lds20
-rw-r--r--board/esd/ocrtc/u-boot.lds4
-rw-r--r--board/esd/pci405/pci405.c8
-rw-r--r--board/esd/pci405/u-boot.lds19
-rw-r--r--board/esd/plu405/plu405.c10
-rw-r--r--board/esd/plu405/u-boot.lds7
-rw-r--r--board/esd/pmc405/u-boot.lds19
-rw-r--r--board/esd/pmc440/cmd_pmc440.c2
-rw-r--r--board/esd/pmc440/pmc440.c59
-rw-r--r--board/esd/pmc440/u-boot-nand.lds4
-rw-r--r--board/esd/pmc440/u-boot.lds7
-rw-r--r--board/esd/tasreg/tasreg.c7
-rw-r--r--board/esd/tasreg/u-boot.lds4
-rw-r--r--board/esd/voh405/u-boot.lds20
-rw-r--r--board/esd/voh405/voh405.c10
-rw-r--r--board/esd/vom405/u-boot.lds7
-rw-r--r--board/esd/vom405/vom405.c17
-rw-r--r--board/esd/wuh405/u-boot.lds19
-rw-r--r--board/esd/wuh405/wuh405.c18
-rw-r--r--board/esteem192e/u-boot.lds4
-rw-r--r--board/etin/debris/debris.c10
-rw-r--r--board/etx094/u-boot.lds4
-rw-r--r--board/evb4510/u-boot.lds2
-rw-r--r--board/evb64260/u-boot.lds4
-rw-r--r--board/exbitgen/u-boot.lds4
-rw-r--r--board/fads/fads.h4
-rw-r--r--board/fads/u-boot.lds4
-rw-r--r--board/flagadm/u-boot.lds4
-rw-r--r--board/freescale/m5249evb/u-boot.lds4
-rw-r--r--board/freescale/m5253demo/u-boot.lds3
-rw-r--r--board/freescale/m5253evbe/u-boot.lds3
-rw-r--r--board/freescale/m5271evb/u-boot.lds3
-rw-r--r--board/freescale/m5272c3/u-boot.lds3
-rw-r--r--board/freescale/m5275evb/u-boot.lds3
-rw-r--r--board/freescale/m5282evb/u-boot.lds3
-rw-r--r--board/freescale/m53017evb/u-boot.lds3
-rw-r--r--board/freescale/m5329evb/u-boot.lds3
-rw-r--r--board/freescale/m5373evb/u-boot.lds3
-rw-r--r--board/freescale/m547xevb/u-boot.lds3
-rw-r--r--board/freescale/m548xevb/u-boot.lds3
-rw-r--r--board/freescale/mpc7448hpc2/u-boot.lds4
-rw-r--r--board/freescale/mpc8536ds/u-boot.lds4
-rw-r--r--board/freescale/mpc8540ads/u-boot.lds4
-rw-r--r--board/freescale/mpc8541cds/u-boot.lds4
-rw-r--r--board/freescale/mpc8544ds/u-boot.lds4
-rw-r--r--board/freescale/mpc8548cds/u-boot.lds4
-rw-r--r--board/freescale/mpc8555cds/u-boot.lds4
-rw-r--r--board/freescale/mpc8560ads/u-boot.lds4
-rw-r--r--board/freescale/mpc8568mds/u-boot.lds4
-rw-r--r--board/freescale/mpc8572ds/u-boot.lds4
-rw-r--r--board/freescale/mpc8610hpcd/u-boot.lds4
-rw-r--r--board/freescale/mpc8641hpcn/u-boot.lds4
-rw-r--r--board/freescale/mx31ads/u-boot.lds2
-rw-r--r--board/g2000/u-boot.lds20
-rw-r--r--board/gaisler/gr_cpci_ax2000/u-boot.lds4
-rw-r--r--board/gaisler/gr_ep2s60/u-boot.lds4
-rw-r--r--board/gaisler/gr_xc3s_1500/u-boot.lds4
-rw-r--r--board/gaisler/grsim/u-boot.lds4
-rw-r--r--board/gaisler/grsim_leon2/u-boot.lds4
-rw-r--r--board/gcplus/u-boot.lds2
-rw-r--r--board/gdsys/gdppc440etx/u-boot.lds4
-rw-r--r--board/gdsys/neo/u-boot.lds4
-rw-r--r--board/gen860t/u-boot-flashenv.lds4
-rw-r--r--board/gen860t/u-boot.lds4
-rw-r--r--board/genietv/u-boot.lds4
-rw-r--r--board/gth/u-boot.lds4
-rw-r--r--board/gth2/u-boot.lds2
-rw-r--r--board/hermes/u-boot.lds4
-rw-r--r--board/hymod/u-boot.lds4
-rw-r--r--board/icu862/u-boot.lds4
-rw-r--r--board/idmr/u-boot.lds3
-rw-r--r--board/impa7/u-boot.lds2
-rw-r--r--board/imx31_litekit/u-boot.lds2
-rw-r--r--board/imx31_phycore/u-boot.lds2
-rw-r--r--board/incaip/u-boot.lds2
-rw-r--r--board/innokom/u-boot.lds2
-rw-r--r--board/ip860/u-boot.lds4
-rw-r--r--board/ivm/u-boot.lds4
-rw-r--r--board/ixdp425/u-boot.lds2
-rw-r--r--board/jse/u-boot.lds4
-rw-r--r--board/kb9202/u-boot.lds2
-rw-r--r--board/keymile/km8xx/km8xx.c4
-rw-r--r--board/keymile/mgcoge/mgcoge.c4
-rw-r--r--board/korat/u-boot-F7FC.lds4
-rw-r--r--board/korat/u-boot.lds4
-rw-r--r--board/kup/common/kup.h2
-rw-r--r--board/kup/kup4k/kup4k.c1
-rw-r--r--board/kup/kup4k/u-boot.lds4
-rw-r--r--board/kup/kup4x/kup4x.c2
-rw-r--r--board/kup/kup4x/u-boot.lds4
-rw-r--r--board/lantec/u-boot.lds4
-rw-r--r--board/lart/u-boot.lds2
-rw-r--r--board/logodl/u-boot.lds2
-rw-r--r--board/lpc2292sodimm/u-boot.lds2
-rw-r--r--board/lpd7a40x/u-boot.lds2
-rw-r--r--board/lubbock/u-boot.lds2
-rw-r--r--board/lwmon/u-boot.lds4
-rw-r--r--board/lwmon5/u-boot.lds4
-rw-r--r--board/m501sk/m501sk.c5
-rw-r--r--board/m501sk/u-boot.lds2
-rw-r--r--board/mbx8xx/mbx8xx.c14
-rw-r--r--board/mbx8xx/u-boot.lds4
-rw-r--r--board/micronas/vct/u-boot.lds2
-rw-r--r--board/mimc/mimc200/u-boot.lds3
-rw-r--r--board/miromico/hammerhead/u-boot.lds3
-rw-r--r--board/ml2/u-boot.lds4
-rw-r--r--board/modnet50/u-boot.lds2
-rw-r--r--board/mousse/u-boot.lds4
-rw-r--r--board/mp2usb/u-boot.lds2
-rw-r--r--board/mpc8540eval/u-boot.lds4
-rw-r--r--board/mpl/mip405/u-boot.lds4
-rw-r--r--board/mpl/pip405/u-boot.lds4
-rw-r--r--board/mpl/vcma9/cmd_vcma9.c11
-rw-r--r--board/mpl/vcma9/u-boot.lds2
-rw-r--r--board/mpr2/u-boot.lds2
-rw-r--r--board/ms7720se/u-boot.lds2
-rw-r--r--board/ms7722se/u-boot.lds2
-rw-r--r--board/ms7750se/u-boot.lds2
-rw-r--r--board/muas3001/muas3001.c4
-rw-r--r--board/munices/u-boot.lds4
-rw-r--r--board/mx1ads/u-boot.lds2
-rw-r--r--board/mx1fs2/u-boot.lds2
-rw-r--r--board/nc650/u-boot.lds4
-rw-r--r--board/netphone/u-boot.lds4
-rw-r--r--board/netstal/common/nm_bsp.c40
-rw-r--r--board/netstal/hcu4/u-boot.lds4
-rw-r--r--board/netstal/hcu5/u-boot.lds4
-rw-r--r--board/netstal/mcu25/u-boot.lds4
-rw-r--r--board/netstar/eeprom.lds2
-rw-r--r--board/netstar/u-boot.lds2
-rw-r--r--board/netta/u-boot.lds4
-rw-r--r--board/netta2/u-boot.lds4
-rw-r--r--board/netvia/u-boot.lds4
-rw-r--r--board/ns9750dev/u-boot.lds2
-rw-r--r--board/nx823/flash.c5
-rw-r--r--board/nx823/nx823.c41
-rw-r--r--board/nx823/u-boot.lds4
-rw-r--r--board/omap1510inn/u-boot.lds2
-rw-r--r--board/omap1610inn/u-boot.lds2
-rw-r--r--board/omap2420h4/u-boot.lds2
-rw-r--r--board/omap3/beagle/u-boot.lds2
-rw-r--r--board/omap3/evm/u-boot.lds2
-rw-r--r--board/omap3/overo/u-boot.lds2
-rw-r--r--board/omap3/pandora/u-boot.lds2
-rw-r--r--board/omap3/zoom1/u-boot.lds2
-rw-r--r--board/omap5912osk/u-boot.lds2
-rw-r--r--board/omap730p2/u-boot.lds2
-rw-r--r--board/pb1x00/u-boot.lds2
-rw-r--r--board/pcippc2/u-boot.lds4
-rw-r--r--board/pcs440ep/pcs440ep.c31
-rw-r--r--board/pcs440ep/u-boot.lds4
-rw-r--r--board/pleb2/u-boot.lds2
-rw-r--r--board/pm854/u-boot.lds4
-rw-r--r--board/pm856/u-boot.lds4
-rw-r--r--board/pn62/pn62.c24
-rw-r--r--board/ppmc7xx/u-boot.lds4
-rw-r--r--board/prodrive/alpr/u-boot.lds4
-rw-r--r--board/prodrive/p3mx/u-boot.lds4
-rw-r--r--board/prodrive/p3p440/u-boot.lds4
-rw-r--r--board/prodrive/pdnb3/u-boot.lds2
-rw-r--r--board/psyent/pci5441/u-boot.lds3
-rw-r--r--board/psyent/pk1c20/u-boot.lds3
-rw-r--r--board/purple/u-boot.lds2
-rw-r--r--board/pxa255_idp/u-boot.lds2
-rw-r--r--board/qemu-mips/u-boot.lds2
-rw-r--r--board/quad100hd/u-boot.lds4
-rw-r--r--board/quantum/u-boot.lds4
-rw-r--r--board/r360mpi/u-boot.lds4
-rw-r--r--board/rbc823/u-boot.lds4
-rw-r--r--board/renesas/MigoR/u-boot.lds2
-rw-r--r--board/renesas/ap325rxa/u-boot.lds2
-rw-r--r--board/renesas/r2dplus/u-boot.lds2
-rw-r--r--board/renesas/r7780mp/u-boot.lds2
-rw-r--r--board/renesas/rsk7203/u-boot.lds2
-rw-r--r--board/renesas/sh7763rdp/u-boot.lds2
-rw-r--r--board/renesas/sh7785lcr/u-boot.lds2
-rw-r--r--board/rmu/u-boot.lds4
-rw-r--r--board/rsdproto/u-boot.lds4
-rw-r--r--board/samsung/smdk2400/u-boot.lds2
-rw-r--r--board/samsung/smdk2410/u-boot.lds2
-rw-r--r--board/samsung/smdk6400/u-boot-nand.lds2
-rw-r--r--board/sandburst/common/sb_common.c4
-rw-r--r--board/sandburst/common/sb_common.h1
-rw-r--r--board/sandburst/karef/karef.c29
-rw-r--r--board/sandburst/karef/u-boot.lds4
-rw-r--r--board/sandburst/metrobox/metrobox.c29
-rw-r--r--board/sandburst/metrobox/u-boot.lds4
-rw-r--r--board/sbc2410x/u-boot.lds2
-rw-r--r--board/sbc405/u-boot.lds4
-rw-r--r--board/sbc8548/u-boot.lds4
-rw-r--r--board/sbc8560/u-boot.lds4
-rw-r--r--board/sbc8641d/u-boot.lds4
-rw-r--r--board/sc3/u-boot.lds4
-rw-r--r--board/sc520_cdp/sc520_cdp.c18
-rw-r--r--board/sc520_cdp/u-boot.lds2
-rw-r--r--board/sc520_spunk/u-boot.lds2
-rw-r--r--board/scb9328/u-boot.lds2
-rw-r--r--board/shannon/u-boot.lds2
-rw-r--r--board/siemens/CCM/u-boot.lds4
-rw-r--r--board/siemens/IAD210/IAD210.c14
-rw-r--r--board/siemens/IAD210/u-boot.lds4
-rw-r--r--board/siemens/SMN42/u-boot.lds2
-rw-r--r--board/siemens/pcu_e/u-boot.lds4
-rw-r--r--board/sixnet/sixnet.c11
-rw-r--r--board/sixnet/u-boot.lds4
-rw-r--r--board/snmc/qs850/u-boot.lds4
-rw-r--r--board/snmc/qs860t/u-boot.lds4
-rw-r--r--board/socrates/u-boot.lds4
-rw-r--r--board/spc1920/u-boot.lds4
-rw-r--r--board/spd8xx/u-boot.lds4
-rw-r--r--board/ssv/adnpesc1/u-boot.lds2
-rw-r--r--board/st/nmdk8815/u-boot.lds2
-rw-r--r--board/stxgp3/u-boot.lds4
-rw-r--r--board/stxssa/u-boot.lds4
-rw-r--r--board/stxxtc/u-boot.lds4
-rw-r--r--board/svm_sc8xx/u-boot.lds4
-rw-r--r--board/sx1/u-boot.lds2
-rw-r--r--board/tb0229/u-boot.lds2
-rw-r--r--board/tqc/tqm85xx/u-boot.lds4
-rw-r--r--board/tqc/tqm8xx/tqm8xx.c3
-rw-r--r--board/tqc/tqm8xx/u-boot.lds4
-rw-r--r--board/trab/u-boot.lds2
-rw-r--r--board/trizepsiv/u-boot.lds2
-rw-r--r--board/uc100/u-boot.lds4
-rw-r--r--board/v37/u-boot.lds4
-rw-r--r--board/v38b/v38b.c12
-rw-r--r--board/voiceblue/eeprom.lds2
-rw-r--r--board/voiceblue/u-boot.lds2
-rw-r--r--board/w7o/u-boot.lds4
-rw-r--r--board/wepep250/u-boot.lds2
-rw-r--r--board/westel/amx860/u-boot.lds4
-rw-r--r--board/xaeniax/u-boot.lds2
-rw-r--r--board/xes/xpedite5200/u-boot.lds4
-rw-r--r--board/xes/xpedite5370/u-boot.lds4
-rw-r--r--board/xilinx/microblaze-generic/u-boot.lds2
-rw-r--r--board/xilinx/ml300/u-boot.lds4
-rw-r--r--board/xilinx/ppc405-generic/u-boot-ram.lds4
-rw-r--r--board/xilinx/ppc405-generic/u-boot-rom.lds4
-rw-r--r--board/xilinx/ppc440-generic/u-boot-ram.lds4
-rw-r--r--board/xilinx/ppc440-generic/u-boot-rom.lds4
-rw-r--r--board/xilinx/xilinx_enet/emac_adapter.c8
-rw-r--r--board/xm250/u-boot.lds2
-rw-r--r--board/xpedite1k/u-boot.lds4
-rw-r--r--board/xpedite1k/u-boot.lds.debug4
-rw-r--r--board/xpedite1k/xpedite1k.c51
-rw-r--r--board/xsengine/u-boot.lds2
-rw-r--r--board/zeus/u-boot.lds4
-rw-r--r--board/zylonite/u-boot.lds2
-rw-r--r--common/Makefile2
-rw-r--r--common/cmd_bdinfo.c166
-rw-r--r--common/cmd_elf.c6
-rw-r--r--common/cmd_flash.c18
-rw-r--r--common/cmd_ide.c10
-rw-r--r--common/cmd_jffs2.c1731
-rw-r--r--common/cmd_mtdparts.c1986
-rw-r--r--common/cmd_nand.c10
-rw-r--r--common/cmd_nvedit.c24
-rw-r--r--common/cmd_ubifs.c132
-rw-r--r--common/lynxkdi.c2
-rw-r--r--cpu/arm920t/at91rm9200/ether.c8
-rw-r--r--cpu/arm926ejs/at91/u-boot.lds2
-rw-r--r--cpu/i386/Makefile2
-rw-r--r--cpu/i386/cpu.c4
-rw-r--r--cpu/i386/exceptions.c229
-rw-r--r--cpu/i386/interrupts.c426
-rw-r--r--cpu/i386/sc520/Makefile4
-rw-r--r--cpu/i386/sc520/sc520.c279
-rw-r--r--cpu/i386/sc520/sc520_pci.c171
-rw-r--r--cpu/i386/sc520/sc520_ssi.c92
-rw-r--r--cpu/i386/sc520/sc520_timer.c82
-rw-r--r--cpu/i386/start.S41
-rw-r--r--cpu/i386/timer.c211
-rw-r--r--cpu/ixp/npe/npe.c36
-rw-r--r--cpu/mpc512x/cpu.c6
-rw-r--r--cpu/mpc5xx/u-boot.lds4
-rw-r--r--cpu/mpc5xxx/cpu.c7
-rw-r--r--cpu/mpc5xxx/u-boot-customlayout.lds4
-rw-r--r--cpu/mpc5xxx/u-boot.lds4
-rw-r--r--cpu/mpc8220/u-boot.lds4
-rw-r--r--cpu/mpc824x/u-boot.lds4
-rw-r--r--cpu/mpc8260/ether_fcc.c4
-rw-r--r--cpu/mpc8260/ether_scc.c4
-rw-r--r--cpu/mpc8260/u-boot.lds4
-rw-r--r--cpu/mpc83xx/u-boot.lds4
-rw-r--r--cpu/ppc4xx/cpu_init.c27
-rw-r--r--disk/part.c2
-rw-r--r--doc/README.enetaddr99
-rw-r--r--drivers/misc/ali512x.c2
-rw-r--r--drivers/net/3c589.c7
-rw-r--r--drivers/net/4xx_enet.c13
-rw-r--r--drivers/net/bcm570x.c4
-rw-r--r--drivers/net/bcm570x_lm.h2
-rw-r--r--drivers/net/bfin_mac.c16
-rw-r--r--drivers/net/bfin_mac.h2
-rw-r--r--drivers/net/cs8900.c56
-rw-r--r--drivers/net/dc2114x.c9
-rw-r--r--drivers/net/dm9000x.c26
-rw-r--r--drivers/net/enc28j60.c4
-rw-r--r--drivers/net/fsl_mcdmafec.c11
-rw-r--r--drivers/net/ks8695eth.c8
-rw-r--r--drivers/net/lan91c96.c75
-rw-r--r--drivers/net/mcffec.c10
-rw-r--r--drivers/net/rtl8019.c14
-rw-r--r--drivers/net/rtl8169.c2
-rw-r--r--drivers/net/s3c4510b_eth.c2
-rw-r--r--drivers/net/s3c4510b_eth.h2
-rw-r--r--drivers/net/sh_eth.c28
-rw-r--r--drivers/net/smc91111.c72
-rw-r--r--drivers/net/smc911x.c14
-rw-r--r--drivers/net/tigon3.c7
-rw-r--r--drivers/net/xilinx_emac.c12
-rw-r--r--drivers/net/xilinx_emaclite.c11
-rw-r--r--examples/mips.lds2
-rw-r--r--examples/nios.lds2
-rw-r--r--examples/nios2.lds3
-rw-r--r--examples/sparc.lds2
-rw-r--r--fs/Makefile1
-rw-r--r--fs/ubifs/Makefile52
-rw-r--r--fs/ubifs/budget.c113
-rw-r--r--fs/ubifs/crc16.c60
-rw-r--r--fs/ubifs/crc16.h30
-rw-r--r--fs/ubifs/debug.c156
-rw-r--r--fs/ubifs/debug.h392
-rw-r--r--fs/ubifs/io.c316
-rw-r--r--fs/ubifs/key.h557
-rw-r--r--fs/ubifs/log.c104
-rw-r--r--fs/ubifs/lprops.c842
-rw-r--r--fs/ubifs/lpt.c1105
-rw-r--r--fs/ubifs/lpt_commit.c171
-rw-r--r--fs/ubifs/master.c341
-rw-r--r--fs/ubifs/misc.h310
-rw-r--r--fs/ubifs/orphan.c316
-rw-r--r--fs/ubifs/recovery.c1249
-rw-r--r--fs/ubifs/replay.c1070
-rw-r--r--fs/ubifs/sb.c324
-rw-r--r--fs/ubifs/scan.c362
-rw-r--r--fs/ubifs/super.c1189
-rw-r--r--fs/ubifs/tnc.c2767
-rw-r--r--fs/ubifs/tnc_commit.c1102
-rw-r--r--fs/ubifs/tnc_misc.c435
-rw-r--r--fs/ubifs/ubifs-media.h751
-rw-r--r--fs/ubifs/ubifs.c687
-rw-r--r--fs/ubifs/ubifs.h2173
-rw-r--r--include/ali512x.h (renamed from include/asm-i386/ic/ali512x.h)0
-rw-r--r--include/asm-arm/u-boot.h5
-rw-r--r--include/asm-avr32/u-boot.h1
-rw-r--r--include/asm-blackfin/u-boot.h1
-rw-r--r--include/asm-i386/interrupt.h48
-rw-r--r--include/asm-i386/u-boot-i386.h13
-rw-r--r--include/asm-i386/u-boot.h1
-rw-r--r--include/asm-m68k/u-boot.h13
-rw-r--r--include/asm-microblaze/u-boot.h1
-rw-r--r--include/asm-mips/u-boot.h1
-rw-r--r--include/asm-nios/u-boot.h1
-rw-r--r--include/asm-nios2/u-boot.h1
-rw-r--r--include/asm-ppc/u-boot.h14
-rw-r--r--include/asm-ppc/unaligned.h16
-rw-r--r--include/asm-sh/u-boot.h1
-rw-r--r--include/asm-sparc/u-boot.h12
-rw-r--r--include/common.h9
-rw-r--r--include/config_cmd_all.h1
-rw-r--r--include/configs/ADNPESC1.h4
-rw-r--r--include/configs/Alaska8220.h4
-rw-r--r--include/configs/BAB7xx.h4
-rw-r--r--include/configs/BC3450.h2
-rw-r--r--include/configs/CATcenter.h4
-rw-r--r--include/configs/CPCI4052.h6
-rw-r--r--include/configs/CPCI405AB.h6
-rw-r--r--include/configs/DASA_SIM.h4
-rw-r--r--include/configs/DB64360.h4
-rw-r--r--include/configs/DB64460.h4
-rw-r--r--include/configs/DK1C20.h4
-rw-r--r--include/configs/DK1S10.h4
-rw-r--r--include/configs/DU405.h14
-rw-r--r--include/configs/ELPPC.h4
-rw-r--r--include/configs/FPS850L.h2
-rw-r--r--include/configs/FPS860L.h2
-rw-r--r--include/configs/HH405.h17
-rw-r--r--include/configs/IAD210.h1
-rw-r--r--include/configs/LANTEC.h4
-rw-r--r--include/configs/MBX860T.h2
-rw-r--r--include/configs/MHPC.h4
-rw-r--r--include/configs/MIP405.h4
-rw-r--r--include/configs/ML2.h4
-rw-r--r--include/configs/MPC8266ADS.h4
-rw-r--r--include/configs/NC650.h4
-rw-r--r--include/configs/NETTA.h4
-rw-r--r--include/configs/PPChameleonEVB.h4
-rw-r--r--include/configs/R360MPI.h4
-rw-r--r--include/configs/RBC823.h4
-rw-r--r--include/configs/RPXClassic.h1
-rw-r--r--include/configs/Rattler.h4
-rw-r--r--include/configs/SIMPC8313.h2
-rw-r--r--include/configs/SXNI855T.h4
-rw-r--r--include/configs/TB5200.h2
-rw-r--r--include/configs/TQM5200.h2
-rw-r--r--include/configs/TQM823L.h2
-rw-r--r--include/configs/TQM823M.h2
-rw-r--r--include/configs/TQM834x.h2
-rw-r--r--include/configs/TQM850L.h2
-rw-r--r--include/configs/TQM850M.h2
-rw-r--r--include/configs/TQM855L.h2
-rw-r--r--include/configs/TQM855M.h2
-rw-r--r--include/configs/TQM85xx.h4
-rw-r--r--include/configs/TQM860L.h2
-rw-r--r--include/configs/TQM860M.h2
-rw-r--r--include/configs/TQM862L.h2
-rw-r--r--include/configs/TQM862M.h2
-rw-r--r--include/configs/TQM866M.h2
-rw-r--r--include/configs/XPEDITE1K.h1
-rw-r--r--include/configs/ZUMA.h4
-rw-r--r--include/configs/apollon.h2
-rw-r--r--include/configs/cm5200.h2
-rw-r--r--include/configs/cmc_pu2.h1
-rw-r--r--include/configs/debris.h4
-rw-r--r--include/configs/digsy_mtc.h346
-rw-r--r--include/configs/eNET.h16
-rw-r--r--include/configs/ep7312.h4
-rw-r--r--include/configs/ep8260.h4
-rw-r--r--include/configs/fx12mm.h2
-rw-r--r--include/configs/hymod.h4
-rw-r--r--include/configs/idmr.h2
-rw-r--r--include/configs/impa7.h4
-rw-r--r--include/configs/imx31_litekit.h2
-rw-r--r--include/configs/imx31_phycore.h2
-rw-r--r--include/configs/incaip.h4
-rw-r--r--include/configs/innokom.h4
-rw-r--r--include/configs/microblaze-generic.h2
-rw-r--r--include/configs/modnet50.h4
-rw-r--r--include/configs/motionpro.h2
-rw-r--r--include/configs/mx1fs2.h4
-rw-r--r--include/configs/mx31ads.h2
-rw-r--r--include/configs/netstar.h2
-rw-r--r--include/configs/omap2420h4.h4
-rw-r--r--include/configs/qong.h2
-rw-r--r--include/configs/sc3.h2
-rw-r--r--include/configs/sc520_cdp.h22
-rw-r--r--include/configs/sc520_spunk.h18
-rw-r--r--include/configs/smmaco4.h2
-rw-r--r--include/configs/trab.h2
-rw-r--r--include/configs/v37.h4
-rw-r--r--include/configs/v38b.h1
-rw-r--r--include/configs/vct.h2
-rw-r--r--include/configs/virtlab2.h2
-rw-r--r--include/configs/voiceblue.h2
-rw-r--r--include/configs/xilinx-ppc.h4
-rw-r--r--include/configs/xsengine.h4
-rw-r--r--include/linux/lzo.h44
-rw-r--r--include/linux/math64.h85
-rw-r--r--include/linux/unaligned/access_ok.h66
-rw-r--r--include/linux/unaligned/generic.h71
-rw-r--r--include/net.h6
-rw-r--r--include/ubi_uboot.h9
-rw-r--r--lib_arm/board.c47
-rw-r--r--lib_blackfin/board.c48
-rw-r--r--lib_generic/lzo/Makefile46
-rw-r--r--lib_generic/lzo/lzo1x_decompress.c245
-rw-r--r--lib_generic/lzo/lzodefs.h43
-rw-r--r--lib_generic/vsprintf.c479
-rw-r--r--lib_i386/Makefile4
-rw-r--r--lib_i386/board.c44
-rw-r--r--lib_i386/interrupts.c159
-rw-r--r--lib_i386/pcat_interrupts.c165
-rw-r--r--lib_i386/pcat_timer.c102
-rw-r--r--lib_i386/timer.c107
-rw-r--r--lib_m68k/board.c38
-rw-r--r--lib_microblaze/board.c8
-rw-r--r--lib_mips/board.c8
-rw-r--r--lib_nios/board.c5
-rw-r--r--lib_nios2/board.c5
-rw-r--r--lib_ppc/board.c97
-rw-r--r--lib_sh/board.c10
-rw-r--r--lib_sparc/board.c19
-rw-r--r--nand_spl/board/amcc/acadia/u-boot.lds2
-rw-r--r--nand_spl/board/amcc/bamboo/u-boot.lds2
-rw-r--r--nand_spl/board/amcc/canyonlands/u-boot.lds2
-rw-r--r--nand_spl/board/amcc/kilauea/u-boot.lds2
-rw-r--r--nand_spl/board/amcc/sequoia/u-boot.lds2
-rw-r--r--nand_spl/board/freescale/mpc8313erdb/u-boot.lds2
-rw-r--r--nand_spl/board/samsung/smdk6400/u-boot.lds2
-rw-r--r--nand_spl/board/sheldon/simpc8313/u-boot.lds2
-rw-r--r--net/bootp.c29
-rw-r--r--net/eth.c69
-rw-r--r--net/net.c30
-rw-r--r--net/nfs.c10
-rw-r--r--net/tftp.c10
-rw-r--r--onenand_ipl/board/apollon/u-boot.onenand.lds2
-rw-r--r--post/cpu/mpc8xx/ether.c4
618 files changed, 23671 insertions, 5362 deletions
diff --git a/MAKEALL b/MAKEALL
index ed9e5ed..32d95db 100755
--- a/MAKEALL
+++ b/MAKEALL
@@ -47,6 +47,7 @@ LIST_5xxx=" \
BC3450 \
cm5200 \
cpci5200 \
+ digsy_mtc \
EVAL5200 \
fo300 \
icecube_5100 \
diff --git a/Makefile b/Makefile
index 61bae6d..63b9909 100644
--- a/Makefile
+++ b/Makefile
@@ -210,6 +210,7 @@ OBJS := $(addprefix $(obj),$(OBJS))
LIBS = lib_generic/libgeneric.a
LIBS += lib_generic/lzma/liblzma.a
+LIBS += lib_generic/lzo/liblzo.a
LIBS += $(shell if [ -f board/$(VENDOR)/common/Makefile ]; then echo \
"board/$(VENDOR)/common/lib$(VENDOR).a"; fi)
LIBS += cpu/$(CPU)/lib$(CPU).a
@@ -221,7 +222,8 @@ LIBS += cpu/ixp/npe/libnpe.a
endif
LIBS += lib_$(ARCH)/lib$(ARCH).a
LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a \
- fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a fs/yaffs2/libyaffs2.a
+ fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a fs/yaffs2/libyaffs2.a \
+ fs/ubifs/libubifs.a
LIBS += net/libnet.a
LIBS += disk/libdisk.a
LIBS += drivers/bios_emulator/libatibiosemu.a
@@ -527,6 +529,22 @@ cm5200_config: unconfig
cpci5200_config: unconfig
@$(MKCONFIG) -a cpci5200 ppc mpc5xxx cpci5200 esd
+digsy_mtc_config \
+digsy_mtc_LOWBOOT_config \
+digsy_mtc_RAMBOOT_config: unconfig
+ @mkdir -p $(obj)include
+ @mkdir -p $(obj)board/digsy_mtc
+ @ >$(obj)include/config.h
+ @[ -z "$(findstring LOWBOOT_,$@)" ] || \
+ { echo "TEXT_BASE = 0xFF000000" >$(obj)board/digsy_mtc/config.tmp ; \
+ echo "... with LOWBOOT configuration" ; \
+ }
+ @[ -z "$(findstring RAMBOOT_,$@)" ] || \
+ { echo "TEXT_BASE = 0x00100000" >$(obj)board/digsy_mtc/config.tmp ; \
+ echo "... with RAMBOOT configuration" ; \
+ }
+ @$(MKCONFIG) -a digsy_mtc ppc mpc5xxx digsy_mtc
+
hmi1001_config: unconfig
@$(MKCONFIG) hmi1001 ppc mpc5xxx hmi1001
diff --git a/README b/README
index 46181a4..32d9acd 100644
--- a/README
+++ b/README
@@ -636,6 +636,7 @@ The following options need to be configured:
CONFIG_CMD_MISC Misc functions like sleep etc
CONFIG_CMD_MMC * MMC memory mapped support
CONFIG_CMD_MII * MII utility commands
+ CONFIG_CMD_MTDPARTS * MTD partition support
CONFIG_CMD_NAND * NAND support
CONFIG_CMD_NET bootp, tftpboot, rarpboot
CONFIG_CMD_PCA953X * PCA953x I2C gpio commands
diff --git a/board/AtmarkTechno/suzaku/u-boot.lds b/board/AtmarkTechno/suzaku/u-boot.lds
index b38f648..5a08680 100644
--- a/board/AtmarkTechno/suzaku/u-boot.lds
+++ b/board/AtmarkTechno/suzaku/u-boot.lds
@@ -38,7 +38,7 @@ SECTIONS
.rodata ALIGN(0x4):
{
__rodata_start = .;
- *(.rodata)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
__rodata_end = .;
}
diff --git a/board/BuS/EB+MCF-EV123/u-boot.lds b/board/BuS/EB+MCF-EV123/u-boot.lds
index b22b332..3450793 100644
--- a/board/BuS/EB+MCF-EV123/u-boot.lds
+++ b/board/BuS/EB+MCF-EV123/u-boot.lds
@@ -73,8 +73,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/LEOX/elpt860/u-boot.lds b/board/LEOX/elpt860/u-boot.lds
index 9b9b980..c6b1f94 100644
--- a/board/LEOX/elpt860/u-boot.lds
+++ b/board/LEOX/elpt860/u-boot.lds
@@ -87,10 +87,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/MAI/AmigaOneG3SE/enet.c b/board/MAI/AmigaOneG3SE/enet.c
index 0b4dfe6..ac969a9 100644
--- a/board/MAI/AmigaOneG3SE/enet.c
+++ b/board/MAI/AmigaOneG3SE/enet.c
@@ -600,7 +600,7 @@ static int eth_3com_init (struct eth_device *dev, bd_t * bis)
ias_cmd = (struct descriptor *) &tx_ring[tx_cur];
ias_cmd->status = cpu_to_le32 (1 << 31); /* set DnIndicate bit. */
ias_cmd->next = 0;
- ias_cmd->addr = cpu_to_le32 ((u32) & bis->bi_enetaddr[0]);
+ ias_cmd->addr = cpu_to_le32 ((u32) dev->enetaddr);
ias_cmd->length = cpu_to_le32 (6 | LAST_FRAG);
/* Tell the adapter where the TX ring is located */
@@ -787,6 +787,10 @@ static void read_hw_addr (struct eth_device *dev, bd_t * bis)
unsigned int checksum = 0;
int i, j, timer;
+ /* First, try the env ... if that works, we're all done! */
+ if (eth_getenv_enetaddr("ethaddr", hw_addr))
+ goto Done;
+
/* Read the station address from the EEPROM. */
EL3WINDOW (dev, 0);
@@ -827,40 +831,10 @@ static void read_hw_addr (struct eth_device *dev, bd_t * bis)
hw_addr[j + 1] = (u8) ((ETH_INW (dev, j) >> 8) & 0xff);
}
- for (i = 0; i < ETH_ALEN; i++) {
- if (hw_addr[i] != bis->bi_enetaddr[i]) {
-/* printf("Warning: HW address don't match:\n"); */
-/* printf("Address in 3Com Window 2 is " */
-/* "%02X:%02X:%02X:%02X:%02X:%02X\n", */
-/* hw_addr[0], hw_addr[1], hw_addr[2], */
-/* hw_addr[3], hw_addr[4], hw_addr[5]); */
-/* printf("Address used by U-Boot is " */
-/* "%02X:%02X:%02X:%02X:%02X:%02X\n", */
-/* bis->bi_enetaddr[0], bis->bi_enetaddr[1], */
-/* bis->bi_enetaddr[2], bis->bi_enetaddr[3], */
-/* bis->bi_enetaddr[4], bis->bi_enetaddr[5]); */
-/* goto Done; */
- char buffer[256];
-
- if (bis->bi_enetaddr[0] == 0
- && bis->bi_enetaddr[1] == 0
- && bis->bi_enetaddr[2] == 0
- && bis->bi_enetaddr[3] == 0
- && bis->bi_enetaddr[4] == 0
- && bis->bi_enetaddr[5] == 0) {
-
- sprintf (buffer,
- "%02X:%02X:%02X:%02X:%02X:%02X",
- hw_addr[0], hw_addr[1], hw_addr[2],
- hw_addr[3], hw_addr[4], hw_addr[5]);
- setenv ("ethaddr", buffer);
- }
- }
- }
-
- for (i = 0; i < ETH_ALEN; i++)
- dev->enetaddr[i] = hw_addr[i];
+ /* Save the result in the environment */
+ eth_setenv_enetaddr("ethaddr", hw_addr);
Done:
+ memcpy(dev->enetaddr, hw_addr, 6);
return;
}
diff --git a/board/MAI/AmigaOneG3SE/u-boot.lds b/board/MAI/AmigaOneG3SE/u-boot.lds
index e107b47..66440da 100644
--- a/board/MAI/AmigaOneG3SE/u-boot.lds
+++ b/board/MAI/AmigaOneG3SE/u-boot.lds
@@ -72,10 +72,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/Marvell/db64360/u-boot.lds b/board/Marvell/db64360/u-boot.lds
index ff2d8b7..632921a 100644
--- a/board/Marvell/db64360/u-boot.lds
+++ b/board/Marvell/db64360/u-boot.lds
@@ -70,10 +70,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/Marvell/db64460/u-boot.lds b/board/Marvell/db64460/u-boot.lds
index ff2d8b7..632921a 100644
--- a/board/Marvell/db64460/u-boot.lds
+++ b/board/Marvell/db64460/u-boot.lds
@@ -70,10 +70,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/RPXClassic/RPXClassic.c b/board/RPXClassic/RPXClassic.c
index 9fdf700..5aa713f 100644
--- a/board/RPXClassic/RPXClassic.c
+++ b/board/RPXClassic/RPXClassic.c
@@ -105,7 +105,7 @@ int checkboard (void)
* board_get_enetaddr -- Read the MAC Address in the I2C EEPROM
*-----------------------------------------------------------------------------
*/
-void board_get_enetaddr (uchar * enet)
+static void board_get_enetaddr(uchar *enet)
{
int i;
char buff[256], *cp;
@@ -142,9 +142,19 @@ void board_get_enetaddr (uchar * enet)
enet[3] |= 0x80;
#endif
- printf ("MAC address = %02x:%02x:%02x:%02x:%02x:%02x\n",
- enet[0], enet[1], enet[2], enet[3], enet[4], enet[5]);
+ printf("MAC address = %pM\n", enet);
+}
+
+int misc_init_r(void)
+{
+ uchar enetaddr[6];
+
+ if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
+ board_get_enetaddr(enetaddr);
+ eth_putenv_enetaddr("ethaddr", enetaddr);
+ }
+ return 0;
}
void rpxclassic_init (void)
diff --git a/board/RPXClassic/u-boot.lds b/board/RPXClassic/u-boot.lds
index 55cb5ec..faa1c6c 100644
--- a/board/RPXClassic/u-boot.lds
+++ b/board/RPXClassic/u-boot.lds
@@ -74,10 +74,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/RPXlite/u-boot.lds b/board/RPXlite/u-boot.lds
index 55cb5ec..faa1c6c 100644
--- a/board/RPXlite/u-boot.lds
+++ b/board/RPXlite/u-boot.lds
@@ -74,10 +74,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/RPXlite_dw/u-boot.lds b/board/RPXlite_dw/u-boot.lds
index 8d17894..7b7b83b 100644
--- a/board/RPXlite_dw/u-boot.lds
+++ b/board/RPXlite_dw/u-boot.lds
@@ -74,10 +74,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/RRvision/u-boot.lds b/board/RRvision/u-boot.lds
index 9fd77f8..17e6fa0 100644
--- a/board/RRvision/u-boot.lds
+++ b/board/RRvision/u-boot.lds
@@ -76,10 +76,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/actux1/u-boot.lds b/board/actux1/u-boot.lds
index ccdb78e..836775f 100644
--- a/board/actux1/u-boot.lds
+++ b/board/actux1/u-boot.lds
@@ -43,7 +43,7 @@ SECTIONS
. = ALIGN (4);
.rodata : {
- *(.rodata)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
. = ALIGN (4);
.data : {
diff --git a/board/actux2/u-boot.lds b/board/actux2/u-boot.lds
index 1131936..0752656 100644
--- a/board/actux2/u-boot.lds
+++ b/board/actux2/u-boot.lds
@@ -45,7 +45,7 @@ SECTIONS
. = ALIGN (4);
.rodata : {
- *(.rodata)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
. = ALIGN (4);
diff --git a/board/actux3/u-boot.lds b/board/actux3/u-boot.lds
index e861955..a69e7db 100644
--- a/board/actux3/u-boot.lds
+++ b/board/actux3/u-boot.lds
@@ -45,7 +45,7 @@ SECTIONS
. = ALIGN (4);
.rodata : {
- *(.rodata)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
. = ALIGN (4);
diff --git a/board/actux4/u-boot.lds b/board/actux4/u-boot.lds
index 0e1155a..10a5da9 100644
--- a/board/actux4/u-boot.lds
+++ b/board/actux4/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
. = ALIGN (4);
.rodata : {
- *(.rodata)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
. = ALIGN (4);
diff --git a/board/adder/u-boot.lds b/board/adder/u-boot.lds
index d97c049..186dfe6 100644
--- a/board/adder/u-boot.lds
+++ b/board/adder/u-boot.lds
@@ -57,10 +57,8 @@ SECTIONS
*(.fixup)
*(.got1)
. = ALIGN(16);
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/ads5121/u-boot.lds b/board/ads5121/u-boot.lds
index a059033..dae3269 100644
--- a/board/ads5121/u-boot.lds
+++ b/board/ads5121/u-boot.lds
@@ -54,10 +54,8 @@ SECTIONS
*(.fixup)
*(.got1)
. = ALIGN(16);
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/altera/dk1c20/u-boot.lds b/board/altera/dk1c20/u-boot.lds
index be77952..98ee8f8 100644
--- a/board/altera/dk1c20/u-boot.lds
+++ b/board/altera/dk1c20/u-boot.lds
@@ -38,7 +38,7 @@ SECTIONS
. = ALIGN(4);
.rodata :
{
- *(.rodata)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
__rodata_end = .;
diff --git a/board/altera/dk1s10/u-boot.lds b/board/altera/dk1s10/u-boot.lds
index be77952..98ee8f8 100644
--- a/board/altera/dk1s10/u-boot.lds
+++ b/board/altera/dk1s10/u-boot.lds
@@ -38,7 +38,7 @@ SECTIONS
. = ALIGN(4);
.rodata :
{
- *(.rodata)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
__rodata_end = .;
diff --git a/board/altera/ep1c20/u-boot.lds b/board/altera/ep1c20/u-boot.lds
index 73dfe9d..e2eb3aa 100644
--- a/board/altera/ep1c20/u-boot.lds
+++ b/board/altera/ep1c20/u-boot.lds
@@ -34,8 +34,7 @@ SECTIONS
*(.text)
*(.text.*)
*(.gnu.linkonce.t*)
- *(.rodata)
- *(.rodata.*)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
*(.gnu.linkonce.r*)
}
. = ALIGN (4);
diff --git a/board/altera/ep1s10/u-boot.lds b/board/altera/ep1s10/u-boot.lds
index 73dfe9d..e2eb3aa 100644
--- a/board/altera/ep1s10/u-boot.lds
+++ b/board/altera/ep1s10/u-boot.lds
@@ -34,8 +34,7 @@ SECTIONS
*(.text)
*(.text.*)
*(.gnu.linkonce.t*)
- *(.rodata)
- *(.rodata.*)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
*(.gnu.linkonce.r*)
}
. = ALIGN (4);
diff --git a/board/altera/ep1s40/u-boot.lds b/board/altera/ep1s40/u-boot.lds
index 73dfe9d..e2eb3aa 100644
--- a/board/altera/ep1s40/u-boot.lds
+++ b/board/altera/ep1s40/u-boot.lds
@@ -34,8 +34,7 @@ SECTIONS
*(.text)
*(.text.*)
*(.gnu.linkonce.t*)
- *(.rodata)
- *(.rodata.*)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
*(.gnu.linkonce.r*)
}
. = ALIGN (4);
diff --git a/board/amcc/acadia/u-boot-nand.lds b/board/amcc/acadia/u-boot-nand.lds
index 799c28f..b769e94 100644
--- a/board/amcc/acadia/u-boot-nand.lds
+++ b/board/amcc/acadia/u-boot-nand.lds
@@ -69,9 +69,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/amcc/acadia/u-boot.lds b/board/amcc/acadia/u-boot.lds
index fd5f3df..b7aa160 100644
--- a/board/amcc/acadia/u-boot.lds
+++ b/board/amcc/acadia/u-boot.lds
@@ -70,10 +70,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/amcc/bamboo/u-boot-nand.lds b/board/amcc/bamboo/u-boot-nand.lds
index 799c28f..b769e94 100644
--- a/board/amcc/bamboo/u-boot-nand.lds
+++ b/board/amcc/bamboo/u-boot-nand.lds
@@ -69,9 +69,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/amcc/bamboo/u-boot.lds b/board/amcc/bamboo/u-boot.lds
index 113418d..997d844 100644
--- a/board/amcc/bamboo/u-boot.lds
+++ b/board/amcc/bamboo/u-boot.lds
@@ -77,10 +77,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/amcc/bubinga/u-boot.lds b/board/amcc/bubinga/u-boot.lds
index fd5f3df..b7aa160 100644
--- a/board/amcc/bubinga/u-boot.lds
+++ b/board/amcc/bubinga/u-boot.lds
@@ -70,10 +70,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/amcc/canyonlands/u-boot-nand.lds b/board/amcc/canyonlands/u-boot-nand.lds
index 9f13d03..d18c536 100644
--- a/board/amcc/canyonlands/u-boot-nand.lds
+++ b/board/amcc/canyonlands/u-boot-nand.lds
@@ -69,9 +69,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/amcc/canyonlands/u-boot.lds b/board/amcc/canyonlands/u-boot.lds
index f0db0b2..b768532 100644
--- a/board/amcc/canyonlands/u-boot.lds
+++ b/board/amcc/canyonlands/u-boot.lds
@@ -76,9 +76,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/amcc/ebony/u-boot.lds b/board/amcc/ebony/u-boot.lds
index 17d1ba8..d569a14 100644
--- a/board/amcc/ebony/u-boot.lds
+++ b/board/amcc/ebony/u-boot.lds
@@ -76,10 +76,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/amcc/katmai/u-boot.lds b/board/amcc/katmai/u-boot.lds
index 464bc6e..71a8b69 100644
--- a/board/amcc/katmai/u-boot.lds
+++ b/board/amcc/katmai/u-boot.lds
@@ -73,10 +73,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/amcc/kilauea/u-boot-nand.lds b/board/amcc/kilauea/u-boot-nand.lds
index 799c28f..b769e94 100644
--- a/board/amcc/kilauea/u-boot-nand.lds
+++ b/board/amcc/kilauea/u-boot-nand.lds
@@ -69,9 +69,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/amcc/kilauea/u-boot.lds b/board/amcc/kilauea/u-boot.lds
index 0ac21e3..a44613d 100644
--- a/board/amcc/kilauea/u-boot.lds
+++ b/board/amcc/kilauea/u-boot.lds
@@ -71,9 +71,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/amcc/luan/u-boot.lds b/board/amcc/luan/u-boot.lds
index b66c768..7c1bc82 100644
--- a/board/amcc/luan/u-boot.lds
+++ b/board/amcc/luan/u-boot.lds
@@ -76,10 +76,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/amcc/makalu/u-boot.lds b/board/amcc/makalu/u-boot.lds
index 0ac21e3..a44613d 100644
--- a/board/amcc/makalu/u-boot.lds
+++ b/board/amcc/makalu/u-boot.lds
@@ -71,9 +71,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/amcc/ocotea/u-boot.lds b/board/amcc/ocotea/u-boot.lds
index 8f61873..95cac85 100644
--- a/board/amcc/ocotea/u-boot.lds
+++ b/board/amcc/ocotea/u-boot.lds
@@ -76,10 +76,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/amcc/redwood/u-boot.lds b/board/amcc/redwood/u-boot.lds
index 8362c9b..32eff52 100644
--- a/board/amcc/redwood/u-boot.lds
+++ b/board/amcc/redwood/u-boot.lds
@@ -80,10 +80,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/amcc/sequoia/u-boot-nand.lds b/board/amcc/sequoia/u-boot-nand.lds
index 6e1e169..b580e0b 100644
--- a/board/amcc/sequoia/u-boot-nand.lds
+++ b/board/amcc/sequoia/u-boot-nand.lds
@@ -69,9 +69,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/amcc/sequoia/u-boot.lds b/board/amcc/sequoia/u-boot.lds
index 05152b7..7798722 100644
--- a/board/amcc/sequoia/u-boot.lds
+++ b/board/amcc/sequoia/u-boot.lds
@@ -75,9 +75,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/amcc/taihu/u-boot.lds b/board/amcc/taihu/u-boot.lds
index fd5f3df..b7aa160 100644
--- a/board/amcc/taihu/u-boot.lds
+++ b/board/amcc/taihu/u-boot.lds
@@ -70,10 +70,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/amcc/taishan/u-boot.lds b/board/amcc/taishan/u-boot.lds
index e620808..75b7fc9 100644
--- a/board/amcc/taishan/u-boot.lds
+++ b/board/amcc/taishan/u-boot.lds
@@ -76,10 +76,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/amcc/walnut/u-boot.lds b/board/amcc/walnut/u-boot.lds
index c9472f9..f6cbe13 100644
--- a/board/amcc/walnut/u-boot.lds
+++ b/board/amcc/walnut/u-boot.lds
@@ -70,10 +70,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/amcc/yosemite/u-boot.lds b/board/amcc/yosemite/u-boot.lds
index ccb510e..e31f071 100644
--- a/board/amcc/yosemite/u-boot.lds
+++ b/board/amcc/yosemite/u-boot.lds
@@ -76,10 +76,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/amcc/yucca/u-boot.lds b/board/amcc/yucca/u-boot.lds
index adfa28b..60135b9 100644
--- a/board/amcc/yucca/u-boot.lds
+++ b/board/amcc/yucca/u-boot.lds
@@ -76,10 +76,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/amirix/ap1000/u-boot.lds b/board/amirix/ap1000/u-boot.lds
index 27a6f8b..a4c48d6 100644
--- a/board/amirix/ap1000/u-boot.lds
+++ b/board/amirix/ap1000/u-boot.lds
@@ -79,10 +79,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/apollon/u-boot.lds b/board/apollon/u-boot.lds
index 0aeb437..7fb7e04 100644
--- a/board/apollon/u-boot.lds
+++ b/board/apollon/u-boot.lds
@@ -43,7 +43,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/armadillo/u-boot.lds b/board/armadillo/u-boot.lds
index 49d18f7..cb5a3ba 100644
--- a/board/armadillo/u-boot.lds
+++ b/board/armadillo/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/armltd/versatile/u-boot.lds b/board/armltd/versatile/u-boot.lds
index 6e6e29b..48c2613 100644
--- a/board/armltd/versatile/u-boot.lds
+++ b/board/armltd/versatile/u-boot.lds
@@ -33,7 +33,7 @@ SECTIONS
cpu/arm926ejs/start.o (.text)
*(.text)
}
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
diff --git a/board/assabet/u-boot.lds b/board/assabet/u-boot.lds
index 5507dd3..bd97436 100644
--- a/board/assabet/u-boot.lds
+++ b/board/assabet/u-boot.lds
@@ -37,7 +37,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/atmel/at91rm9200dk/u-boot.lds b/board/atmel/at91rm9200dk/u-boot.lds
index 987b07d..33363c2 100644
--- a/board/atmel/at91rm9200dk/u-boot.lds
+++ b/board/atmel/at91rm9200dk/u-boot.lds
@@ -37,7 +37,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/atmel/atngw100/u-boot.lds b/board/atmel/atngw100/u-boot.lds
index e736adf..a7243f2 100644
--- a/board/atmel/atngw100/u-boot.lds
+++ b/board/atmel/atngw100/u-boot.lds
@@ -36,8 +36,7 @@ SECTIONS
_etext = .;
.rodata : {
- *(.rodata)
- *(.rodata.*)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
. = ALIGN(8);
diff --git a/board/atmel/atstk1000/u-boot.lds b/board/atmel/atstk1000/u-boot.lds
index 0d3b19c..86ef939 100644
--- a/board/atmel/atstk1000/u-boot.lds
+++ b/board/atmel/atstk1000/u-boot.lds
@@ -36,8 +36,7 @@ SECTIONS
_etext = .;
.rodata : {
- *(.rodata)
- *(.rodata.*)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
. = ALIGN(8);
diff --git a/board/atum8548/u-boot.lds b/board/atum8548/u-boot.lds
index 650cb9e..3067846 100644
--- a/board/atum8548/u-boot.lds
+++ b/board/atum8548/u-boot.lds
@@ -78,10 +78,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/c2mon/u-boot.lds b/board/c2mon/u-boot.lds
index ef9a251..61650a8 100644
--- a/board/c2mon/u-boot.lds
+++ b/board/c2mon/u-boot.lds
@@ -73,10 +73,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/cerf250/u-boot.lds b/board/cerf250/u-boot.lds
index 7cf9fdf..a077bc5 100644
--- a/board/cerf250/u-boot.lds
+++ b/board/cerf250/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/cm4008/u-boot.lds b/board/cm4008/u-boot.lds
index e1febe1..e96c45f 100644
--- a/board/cm4008/u-boot.lds
+++ b/board/cm4008/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/cm41xx/u-boot.lds b/board/cm41xx/u-boot.lds
index e1febe1..e96c45f 100644
--- a/board/cm41xx/u-boot.lds
+++ b/board/cm41xx/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/cm5200/u-boot.lds b/board/cm5200/u-boot.lds
index 7bd6d4d..3a72bd3 100644
--- a/board/cm5200/u-boot.lds
+++ b/board/cm5200/u-boot.lds
@@ -55,10 +55,8 @@ SECTIONS
*(.fixup)
*(.got1)
. = ALIGN(16);
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/cmc_pu2/load_sernum_ethaddr.c b/board/cmc_pu2/load_sernum_ethaddr.c
index 354566c..5ef9f20 100644
--- a/board/cmc_pu2/load_sernum_ethaddr.c
+++ b/board/cmc_pu2/load_sernum_ethaddr.c
@@ -66,14 +66,13 @@ int i2c_read (unsigned char chip, unsigned int addr, int alen,
* Internal structure: see struct definition
*/
-void load_sernum_ethaddr (void)
+void misc_init_r(void)
{
struct manufacturer_data data;
- char ethaddr[18];
char serial [9];
unsigned short chksum;
unsigned char *p;
- unsigned short i, is, id;
+ unsigned short i;
#if !defined(CONFIG_HARD_I2C) && !defined(CONFIG_SOFT_I2C)
#error you must define some I2C support (CONFIG_HARD_I2C or CONFIG_SOFT_I2C)
@@ -97,17 +96,6 @@ void load_sernum_ethaddr (void)
return;
}
- /* copy MAC address */
- is = 0;
- id = 0;
- for (i = 0; i < 6; i++) {
- sprintf (&ethaddr[id], "%02x", data.macadr[is++]);
- id += 2;
- if (is < 6)
- ethaddr[id++] = ':';
- }
- ethaddr[id] = '\0'; /* just to be sure */
-
/* copy serial number */
sprintf (serial, "%d", data.serial_number);
@@ -117,6 +105,6 @@ void load_sernum_ethaddr (void)
}
if (getenv("ethaddr") == NULL) {
- setenv ("ethaddr", ethaddr);
+ eth_setenv_enetaddr("ethaddr", data.macadr);
}
}
diff --git a/board/cmc_pu2/u-boot.lds b/board/cmc_pu2/u-boot.lds
index 987b07d..33363c2 100644
--- a/board/cmc_pu2/u-boot.lds
+++ b/board/cmc_pu2/u-boot.lds
@@ -37,7 +37,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/cobra5272/u-boot.lds b/board/cobra5272/u-boot.lds
index bed1177..7e716bb 100644
--- a/board/cobra5272/u-boot.lds
+++ b/board/cobra5272/u-boot.lds
@@ -72,8 +72,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/cogent/u-boot.lds b/board/cogent/u-boot.lds
index 5fd9f79..3ea6f1c 100644
--- a/board/cogent/u-boot.lds
+++ b/board/cogent/u-boot.lds
@@ -61,10 +61,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/cradle/u-boot.lds b/board/cradle/u-boot.lds
index 7cf9fdf..a077bc5 100644
--- a/board/cradle/u-boot.lds
+++ b/board/cradle/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/cray/L1/u-boot.lds b/board/cray/L1/u-boot.lds
index d278866..86c8ecb 100644
--- a/board/cray/L1/u-boot.lds
+++ b/board/cray/L1/u-boot.lds
@@ -85,10 +85,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/csb226/u-boot.lds b/board/csb226/u-boot.lds
index 7cf9fdf..a077bc5 100644
--- a/board/csb226/u-boot.lds
+++ b/board/csb226/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/csb272/u-boot.lds b/board/csb272/u-boot.lds
index af87188..0aa6f8f 100644
--- a/board/csb272/u-boot.lds
+++ b/board/csb272/u-boot.lds
@@ -86,10 +86,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/csb472/u-boot.lds b/board/csb472/u-boot.lds
index 3736377..565e021 100644
--- a/board/csb472/u-boot.lds
+++ b/board/csb472/u-boot.lds
@@ -86,10 +86,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/csb637/u-boot.lds b/board/csb637/u-boot.lds
index d0666ac..3eae0e2 100644
--- a/board/csb637/u-boot.lds
+++ b/board/csb637/u-boot.lds
@@ -37,7 +37,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/dave/B2/u-boot.lds b/board/dave/B2/u-boot.lds
index a6fc6d7..1690b6e 100644
--- a/board/dave/B2/u-boot.lds
+++ b/board/dave/B2/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/dave/PPChameleonEVB/u-boot.lds b/board/dave/PPChameleonEVB/u-boot.lds
index d3e6df9..b36827d 100644
--- a/board/dave/PPChameleonEVB/u-boot.lds
+++ b/board/dave/PPChameleonEVB/u-boot.lds
@@ -80,10 +80,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/davinci/dvevm/u-boot.lds b/board/davinci/dvevm/u-boot.lds
index d86eb36..4d50f2c 100644
--- a/board/davinci/dvevm/u-boot.lds
+++ b/board/davinci/dvevm/u-boot.lds
@@ -34,7 +34,7 @@ SECTIONS
*(.text)
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
diff --git a/board/davinci/schmoogie/u-boot.lds b/board/davinci/schmoogie/u-boot.lds
index d86eb36..4d50f2c 100644
--- a/board/davinci/schmoogie/u-boot.lds
+++ b/board/davinci/schmoogie/u-boot.lds
@@ -34,7 +34,7 @@ SECTIONS
*(.text)
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
diff --git a/board/davinci/sffsdr/u-boot.lds b/board/davinci/sffsdr/u-boot.lds
index d86eb36..4d50f2c 100644
--- a/board/davinci/sffsdr/u-boot.lds
+++ b/board/davinci/sffsdr/u-boot.lds
@@ -34,7 +34,7 @@ SECTIONS
*(.text)
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
diff --git a/board/davinci/sonata/u-boot.lds b/board/davinci/sonata/u-boot.lds
index d86eb36..4d50f2c 100644
--- a/board/davinci/sonata/u-boot.lds
+++ b/board/davinci/sonata/u-boot.lds
@@ -34,7 +34,7 @@ SECTIONS
*(.text)
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
diff --git a/board/dbau1x00/u-boot.lds b/board/dbau1x00/u-boot.lds
index da20de1..9a6cd1b 100644
--- a/board/dbau1x00/u-boot.lds
+++ b/board/dbau1x00/u-boot.lds
@@ -38,7 +38,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/delta/u-boot.lds b/board/delta/u-boot.lds
index 7cf9fdf..a077bc5 100644
--- a/board/delta/u-boot.lds
+++ b/board/delta/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/digsy_mtc/Makefile b/board/digsy_mtc/Makefile
new file mode 100644
index 0000000..7d659e5
--- /dev/null
+++ b/board/digsy_mtc/Makefile
@@ -0,0 +1,32 @@
+
+#
+# Author: Grzegorz Bernacki, Semihalf, gjb@semihalf.com
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)lib$(BOARD).a
+
+COBJS := $(BOARD).o
+
+SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS))
+SOBJS := $(addprefix $(obj),$(SOBJS))
+
+$(LIB): $(obj).depend $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+clean:
+ rm -f $(SOBJS) $(OBJS)
+
+distclean: clean
+ rm -f $(LIB) core *.bak .depend
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/board/digsy_mtc/config.mk b/board/digsy_mtc/config.mk
new file mode 100644
index 0000000..e2f14b0
--- /dev/null
+++ b/board/digsy_mtc/config.mk
@@ -0,0 +1,24 @@
+#
+# Author: Grzegorz Bernacki, Semihalf, gjb@semihalf.com
+#
+
+#
+# digsyMTC board:
+#
+# Valid values for TEXT_BASE are:
+#
+# 0xFFF00000 boot high (standard configuration)
+# 0xFE000000 boot low
+# 0x00100000 boot from RAM (for testing only)
+#
+
+sinclude $(OBJTREE)/board/$(BOARDDIR)/config.tmp
+
+ifndef TEXT_BASE
+## Standard: boot high
+TEXT_BASE = 0xFFF00000
+## For testing: boot from RAM
+# TEXT_BASE = 0x00100000
+endif
+
+PLATFORM_CPPFLAGS += -DTEXT_BASE=$(TEXT_BASE) -I$(TOPDIR)/board
diff --git a/board/digsy_mtc/digsy_mtc.c b/board/digsy_mtc/digsy_mtc.c
new file mode 100644
index 0000000..e231c10
--- /dev/null
+++ b/board/digsy_mtc/digsy_mtc.c
@@ -0,0 +1,307 @@
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2004
+ * Mark Jonas, Freescale Semiconductor, mark.jonas@motorola.com.
+ *
+ * (C) Copyright 2005-2009
+ * Modified for InterControl digsyMTC MPC5200 board by
+ * Frank Bodammer, GCD Hard- & Software GmbH,
+ * frank.bodammer@gcd-solutions.de
+ *
+ * (C) Copyright 2009
+ * Grzegorz Bernacki, Semihalf, gjb@semihalf.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc5xxx.h>
+#include <net.h>
+#include <pci.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include "eeprom.h"
+#include "is42s16800a-7t.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+extern int usb_cpu_init(void);
+
+#ifndef CONFIG_SYS_RAMBOOT
+static void sdram_start(int hi_addr)
+{
+ long hi_addr_bit = hi_addr ? 0x01000000 : 0;
+ long control = SDRAM_CONTROL | hi_addr_bit;
+
+ /* unlock mode register */
+ out_be32((void *)MPC5XXX_SDRAM_CTRL, control | 0x80000000);
+
+ /* precharge all banks */
+ out_be32((void *)MPC5XXX_SDRAM_CTRL, control | 0x80000002);
+
+ /* auto refresh */
+ out_be32((void *)MPC5XXX_SDRAM_CTRL, control | 0x80000004);
+
+ /* set mode register */
+ out_be32((void *)MPC5XXX_SDRAM_MODE, SDRAM_MODE);
+
+ /* normal operation */
+ out_be32((void *)MPC5XXX_SDRAM_CTRL, control);
+}
+#endif
+
+/*
+ * ATTENTION: Although partially referenced initdram does NOT make real use
+ * use of CONFIG_SYS_SDRAM_BASE. The code does not work if
+ * CONFIG_SYS_SDRAM_BASE is something else than 0x00000000.
+ */
+
+phys_size_t initdram(int board_type)
+{
+ ulong dramsize = 0;
+ ulong dramsize2 = 0;
+ uint svr, pvr;
+#ifndef CONFIG_SYS_RAMBOOT
+ ulong test1, test2;
+
+ /* setup SDRAM chip selects */
+ out_be32((void *)MPC5XXX_SDRAM_CS0CFG, 0x0000001C); /* 512MB at 0x0 */
+ out_be32((void *)MPC5XXX_SDRAM_CS1CFG, 0x80000000); /* disabled */
+
+ /* setup config registers */
+ out_be32((void *)MPC5XXX_SDRAM_CONFIG1, SDRAM_CONFIG1);
+ out_be32((void *)MPC5XXX_SDRAM_CONFIG2, SDRAM_CONFIG2);
+
+ /* find RAM size using SDRAM CS0 only */
+ sdram_start(0);
+ test1 = get_ram_size((long *)CONFIG_SYS_SDRAM_BASE, 0x08000000);
+ sdram_start(1);
+ test2 = get_ram_size((long *)CONFIG_SYS_SDRAM_BASE, 0x08000000);
+ if (test1 > test2) {
+ sdram_start(0);
+ dramsize = test1;
+ } else {
+ dramsize = test2;
+ }
+
+ /* memory smaller than 1MB is impossible */
+ if (dramsize < (1 << 20))
+ dramsize = 0;
+
+ /* set SDRAM CS0 size according to the amount of RAM found */
+ if (dramsize > 0) {
+ out_be32((void *)MPC5XXX_SDRAM_CS0CFG,
+ (0x13 + __builtin_ffs(dramsize >> 20) - 1));
+ } else {
+ out_be32((void *)MPC5XXX_SDRAM_CS0CFG, 0); /* disabled */
+ }
+
+ /* let SDRAM CS1 start right after CS0 */
+ out_be32((void *)MPC5XXX_SDRAM_CS1CFG, dramsize + 0x0000001C);
+
+ /* find RAM size using SDRAM CS1 only */
+ test1 = get_ram_size((long *)(CONFIG_SYS_SDRAM_BASE + dramsize),
+ 0x08000000);
+ dramsize2 = test1;
+
+ /* memory smaller than 1MB is impossible */
+ if (dramsize2 < (1 << 20))
+ dramsize2 = 0;
+
+ /* set SDRAM CS1 size according to the amount of RAM found */
+ if (dramsize2 > 0) {
+ out_be32((void *)MPC5XXX_SDRAM_CS1CFG, (dramsize |
+ (0x13 + __builtin_ffs(dramsize2 >> 20) - 1)));
+ } else {
+ out_be32((void *)MPC5XXX_SDRAM_CS1CFG, dramsize); /* disabled */
+ }
+
+#else /* CONFIG_SYS_RAMBOOT */
+
+ /* retrieve size of memory connected to SDRAM CS0 */
+ dramsize = in_be32((void *)MPC5XXX_SDRAM_CS0CFG) & 0xFF;
+ if (dramsize >= 0x13)
+ dramsize = (1 << (dramsize - 0x13)) << 20;
+ else
+ dramsize = 0;
+
+ /* retrieve size of memory connected to SDRAM CS1 */
+ dramsize2 = in_be32((void *)MPC5XXX_SDRAM_CS1CFG) & 0xFF;
+ if (dramsize2 >= 0x13)
+ dramsize2 = (1 << (dramsize2 - 0x13)) << 20;
+ else
+ dramsize2 = 0;
+
+#endif /* CONFIG_SYS_RAMBOOT */
+
+ /*
+ * On MPC5200B we need to set the special configuration delay in the
+ * DDR controller. Please refer to Freescale's AN3221 "MPC5200B SDRAM
+ * Initialization and Configuration", 3.3.1 SDelay--MBAR + 0x0190:
+ *
+ * "The SDelay should be written to a value of 0x00000004. It is
+ * required to account for changes caused by normal wafer processing
+ * parameters."
+ */
+ svr = get_svr();
+ pvr = get_pvr();
+ if ((SVR_MJREV(svr) >= 2) &&
+ (PVR_MAJ(pvr) == 1) && (PVR_MIN(pvr) == 4))
+ out_be32((void *)MPC5XXX_SDRAM_SDELAY, 0x04);
+
+ return dramsize + dramsize2;
+}
+
+int checkboard(void)
+{
+ char *s = getenv("serial#");
+
+ puts ("Board: InterControl digsyMTC");
+ if (s != NULL) {
+ puts(", ");
+ puts(s);
+ }
+ putc('\n');
+
+ return 0;
+}
+
+int board_early_init_r(void)
+{
+ /*
+ * Now, when we are in RAM, enable flash write access for detection
+ * process. Note that CS_BOOT cannot be cleared when executing in
+ * flash.
+ */
+ /* disable CS_BOOT */
+ clrbits_be32((void *)MPC5XXX_ADDECR, (1 << 25));
+ /* enable CS1 */
+ setbits_be32((void *)MPC5XXX_ADDECR, (1 << 17));
+ /* enable CS0 */
+ setbits_be32((void *)MPC5XXX_ADDECR, (1 << 16));
+
+#if defined(CONFIG_USB_OHCI_NEW) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT)
+ /* Low level USB init, required for proper kernel operation */
+ usb_cpu_init();
+#endif
+ return (0);
+}
+
+void board_get_enetaddr (uchar * enet)
+{
+ ushort read = 0;
+ ushort addr_of_eth_addr = 0;
+ ushort len_sys = 0;
+ ushort len_sys_cfg = 0;
+
+ /* check identification word */
+ eeprom_read(EEPROM_ADDR, EEPROM_ADDR_IDENT, (uchar *)&read, 2);
+ if (read != EEPROM_IDENT)
+ return;
+
+ /* calculate offset of config area */
+ eeprom_read(EEPROM_ADDR, EEPROM_ADDR_LEN_SYS, (uchar *)&len_sys, 2);
+ eeprom_read(EEPROM_ADDR, EEPROM_ADDR_LEN_SYSCFG,
+ (uchar *)&len_sys_cfg, 2);
+ addr_of_eth_addr = (len_sys + len_sys_cfg + EEPROM_ADDR_ETHADDR) << 1;
+ if (addr_of_eth_addr >= EEPROM_LEN)
+ return;
+
+ eeprom_read(EEPROM_ADDR, addr_of_eth_addr, enet, 6);
+}
+
+int misc_init_r(void)
+{
+ uchar enetaddr[6];
+
+ if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
+ board_get_enetaddr(enetaddr);
+ eth_setenv_enetaddr("ethaddr", enetaddr);
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_PCI
+static struct pci_controller hose;
+
+extern void pci_mpc5xxx_init(struct pci_controller *);
+
+void pci_init_board(void)
+{
+ pci_mpc5xxx_init(&hose);
+}
+#endif
+
+#ifdef CONFIG_CMD_IDE
+
+#ifdef CONFIG_IDE_RESET
+
+void init_ide_reset(void)
+{
+ debug ("init_ide_reset\n");
+
+ /* set gpio output value to 1 */
+ setbits_be32((void *)MPC5XXX_WU_GPIO_DATA_O, (1 << 25));
+ /* open drain output */
+ setbits_be32((void *)MPC5XXX_WU_GPIO_ODE, (1 << 25));
+ /* direction output */
+ setbits_be32((void *)MPC5XXX_WU_GPIO_DIR, (1 << 25));
+ /* enable gpio */
+ setbits_be32((void *)MPC5XXX_WU_GPIO_ENABLE, (1 << 25));
+
+}
+
+void ide_set_reset(int idereset)
+{
+ debug ("ide_reset(%d)\n", idereset);
+
+ /* set gpio output value to 0 */
+ clrbits_be32((void *)MPC5XXX_WU_GPIO_DATA_O, (1 << 25));
+ /* open drain output */
+ setbits_be32((void *)MPC5XXX_WU_GPIO_ODE, (1 << 25));
+ /* direction output */
+ setbits_be32((void *)MPC5XXX_WU_GPIO_DIR, (1 << 25));
+ /* enable gpio */
+ setbits_be32((void *)MPC5XXX_WU_GPIO_ENABLE, (1 << 25));
+
+ udelay(10000);
+
+ /* set gpio output value to 1 */
+ setbits_be32((void *)MPC5XXX_WU_GPIO_DATA_O, (1 << 25));
+ /* open drain output */
+ setbits_be32((void *)MPC5XXX_WU_GPIO_ODE, (1 << 25));
+ /* direction output */
+ setbits_be32((void *)MPC5XXX_WU_GPIO_DIR, (1 << 25));
+ /* enable gpio */
+ setbits_be32((void *)MPC5XXX_WU_GPIO_ENABLE, (1 << 25));
+}
+#endif /* CONFIG_IDE_RESET */
+
+#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
+void ft_board_setup(void *blob, bd_t *bd)
+{
+ ft_cpu_setup(blob, bd);
+}
+#endif /* defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP) */
+
+#endif /* CONFIG_CMD_IDE */
+
diff --git a/board/digsy_mtc/eeprom.h b/board/digsy_mtc/eeprom.h
new file mode 100644
index 0000000..39e0378
--- /dev/null
+++ b/board/digsy_mtc/eeprom.h
@@ -0,0 +1,32 @@
+/*
+ * (C) Copyright 2009 Semihalf.
+ * Written by: Grzegorz Bernacki <gjb@semihalf.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 anty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+#ifndef CMD_EEPROM_H
+#define CMD_EEPROM_H
+
+#define EEPROM_ADDR CONFIG_SYS_I2C_EEPROM_ADDR
+#define EEPROM_LEN 1024 /* eeprom length */
+#define EEPROM_IDENT 2408 /* identification word */
+#define EEPROM_ADDR_IDENT 0 /* identification word offset */
+#define EEPROM_ADDR_LEN_SYS 2 /* system area lenght offset */
+#define EEPROM_ADDR_LEN_SYSCFG 4 /* system config area length offset */
+#define EEPROM_ADDR_ETHADDR 23 /* ethernet addres offset */
+
+#endif
diff --git a/board/digsy_mtc/is42s16800a-7t.h b/board/digsy_mtc/is42s16800a-7t.h
new file mode 100644
index 0000000..1873ea7
--- /dev/null
+++ b/board/digsy_mtc/is42s16800a-7t.h
@@ -0,0 +1,28 @@
+/*
+ * (C) Copyright 2004-2009
+ * Mark Jonas, Freescale Semiconductor, mark.jonas@motorola.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#define SDRAM_MODE 0x00CD0000
+#define SDRAM_CONTROL 0x505F0000
+#define SDRAM_CONFIG1 0xD2322900
+#define SDRAM_CONFIG2 0x8AD70000
+
diff --git a/board/dnp1110/u-boot.lds b/board/dnp1110/u-boot.lds
index fce2533..13b7bb7 100644
--- a/board/dnp1110/u-boot.lds
+++ b/board/dnp1110/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/eNET/u-boot.lds b/board/eNET/u-boot.lds
index 671305a..4ea424d 100644
--- a/board/eNET/u-boot.lds
+++ b/board/eNET/u-boot.lds
@@ -31,7 +31,7 @@ SECTIONS
.text : { *(.text); }
. = ALIGN(4);
- .rodata : { *(.rodata) *(.rodata.str1.1) *(.rodata.str1.32) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
_i386boot_text_size = SIZEOF(.text) + SIZEOF(.rodata);
diff --git a/board/earthlcd/favr-32-ezkit/u-boot.lds b/board/earthlcd/favr-32-ezkit/u-boot.lds
index ad056b3..0d413a0 100644
--- a/board/earthlcd/favr-32-ezkit/u-boot.lds
+++ b/board/earthlcd/favr-32-ezkit/u-boot.lds
@@ -34,8 +34,7 @@ SECTIONS
_etext = .;
.rodata : {
- *(.rodata)
- *(.rodata.*)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
. = ALIGN(8);
diff --git a/board/eltec/bab7xx/u-boot.lds b/board/eltec/bab7xx/u-boot.lds
index ff2d8b7..632921a 100644
--- a/board/eltec/bab7xx/u-boot.lds
+++ b/board/eltec/bab7xx/u-boot.lds
@@ -70,10 +70,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/eltec/elppc/u-boot.lds b/board/eltec/elppc/u-boot.lds
index ff2d8b7..632921a 100644
--- a/board/eltec/elppc/u-boot.lds
+++ b/board/eltec/elppc/u-boot.lds
@@ -70,10 +70,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/eltec/mhpc/u-boot.lds b/board/eltec/mhpc/u-boot.lds
index 759b412..ee74eb9 100644
--- a/board/eltec/mhpc/u-boot.lds
+++ b/board/eltec/mhpc/u-boot.lds
@@ -63,10 +63,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/emk/top860/u-boot.lds b/board/emk/top860/u-boot.lds
index da23fff..b4e093c 100644
--- a/board/emk/top860/u-boot.lds
+++ b/board/emk/top860/u-boot.lds
@@ -62,10 +62,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/ep7312/u-boot.lds b/board/ep7312/u-boot.lds
index a79bb8c..8c9f624 100644
--- a/board/ep7312/u-boot.lds
+++ b/board/ep7312/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/ep88x/u-boot.lds b/board/ep88x/u-boot.lds
index 1b6e417..dd62e58 100644
--- a/board/ep88x/u-boot.lds
+++ b/board/ep88x/u-boot.lds
@@ -57,9 +57,7 @@ SECTIONS
*(.fixup)
*(.got1)
. = ALIGN(16);
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/eric/u-boot.lds b/board/eric/u-boot.lds
index bf46e18..e62896f 100644
--- a/board/eric/u-boot.lds
+++ b/board/eric/u-boot.lds
@@ -85,10 +85,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/adciop/u-boot.lds b/board/esd/adciop/u-boot.lds
index e918163..2645e84 100644
--- a/board/esd/adciop/u-boot.lds
+++ b/board/esd/adciop/u-boot.lds
@@ -57,11 +57,7 @@ SECTIONS
.plt : { *(.plt) }
.text :
{
- /* WARNING - the following is hand-optimized to fit within */
- /* the sector layout of our flash chips! XXX FIXME XXX */
-
cpu/ppc4xx/start.o (.text)
- cpu/ppc4xx/traps.o (.text)
*(.text)
*(.fixup)
@@ -71,10 +67,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/apc405/apc405.c b/board/esd/apc405/apc405.c
index ac9bbb3..5a02155 100644
--- a/board/esd/apc405/apc405.c
+++ b/board/esd/apc405/apc405.c
@@ -93,7 +93,7 @@ int N_AU_IMAGES = (sizeof(au_image) / sizeof(au_image[0]));
int board_revision(void)
{
unsigned long cntrl0Reg;
- volatile unsigned long value;
+ unsigned long value;
/*
* Get version of APC405 board from GPIO's
diff --git a/board/esd/apc405/u-boot.lds b/board/esd/apc405/u-boot.lds
index 9697cc6..8c01016 100644
--- a/board/esd/apc405/u-boot.lds
+++ b/board/esd/apc405/u-boot.lds
@@ -57,22 +57,7 @@ SECTIONS
.plt : { *(.plt) }
.text :
{
- /* WARNING - the following is hand-optimized to fit within */
- /* the sector layout of our flash chips! XXX FIXME XXX */
-
cpu/ppc4xx/start.o (.text)
- cpu/ppc4xx/traps.o (.text)
- cpu/ppc4xx/interrupts.o (.text)
- cpu/ppc4xx/4xx_uart.o (.text)
- cpu/ppc4xx/cpu_init.o (.text)
- cpu/ppc4xx/speed.o (.text)
- common/dlmalloc.o (.text)
- lib_generic/crc32.o (.text)
- lib_ppc/extable.o (.text)
- lib_generic/zlib.o (.text)
-
-/* . = env_offset;*/
-/* common/env_embedded.o(.text)*/
*(.text)
*(.fixup)
@@ -82,10 +67,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/ar405/ar405.c b/board/esd/ar405/ar405.c
index c4b4b67..14520e1 100644
--- a/board/esd/ar405/ar405.c
+++ b/board/esd/ar405/ar405.c
@@ -24,6 +24,7 @@
#include <common.h>
#include "ar405.h"
#include <asm/processor.h>
+#include <asm/io.h>
#include <command.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -137,18 +138,14 @@ int board_early_init_f (void)
mtdcr (uicvcr, 0x00000001); /* set vect base=0,INT0 highest priority */
mtdcr (uicsr, 0xFFFFFFFF); /* clear all ints */
- *(ushort *) 0xf03000ec = 0x0fff; /* enable all interrupts in fpga */
+ out_be16((void *)0xf03000ec, 0x0fff); /* enable interrupts in fpga */
return 0;
}
-
-/* ------------------------------------------------------------------------- */
-
/*
* Check Board Identity:
*/
-
int checkboard (void)
{
int index;
@@ -192,14 +189,15 @@ int checkboard (void)
#if 1 /* test-only: some internal test routines... */
+#define DIGEN ((void *)0xf03000b4) /* u8 */
+#define DIGOUT ((void *)0xf03000b0) /* u16 */
+#define DIGIN ((void *)0xf03000a0) /* u16 */
+
/*
* Some test routines
*/
int do_digtest(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
- volatile uchar *digen = (volatile uchar *)0xf03000b4;
- volatile ushort *digout = (volatile ushort *)0xf03000b0;
- volatile ushort *digin = (volatile ushort *)0xf03000a0;
int i;
int k;
int start;
@@ -216,7 +214,7 @@ int do_digtest(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
/*
* Enable digital outputs
*/
- *digen = 0x08;
+ out_8(DIGEN, 0x08);
printf("\nStarting digital In-/Out Test from I/O %d to %d (Cntrl-C to abort)...\n",
start, end);
@@ -226,12 +224,13 @@ int do_digtest(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
*/
for (;;) {
for (i=start; i<=end; i++) {
- *digout = 0x0001 << i;
+ out_be16(DIGOUT, 0x0001 << i);
for (k=0; k<200; k++)
udelay(1000);
- if (*digin != (0x0001 << i)) {
- printf("ERROR: OUT=0x%04X, IN=0x%04X\n", 0x0001 << i, *digin);
+ if (in_be16(DIGIN) != (0x0001 << i)) {
+ printf("ERROR: OUT=0x%04X, IN=0x%04X\n",
+ 0x0001 << i, in_be16(DIGIN));
return 0;
}
@@ -255,13 +254,13 @@ U_BOOT_CMD(
#define ERROR_DELTA 256
struct io {
- volatile short val;
+ short val;
short dummy;
};
int do_anatest(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
- volatile short val;
+ short val;
int i;
int volt;
struct io *out;
@@ -274,9 +273,9 @@ int do_anatest(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
volt = 0;
printf("Setting Channel %d to %dV...\n", i, volt);
- out[i].val = (volt * 0x7fff) / 10;
+ out_be16((void *)&(out[i].val), (volt * 0x7fff) / 10);
udelay(10000);
- val = in[i*2].val;
+ val = in_be16((void *)&(in[i*2].val));
printf("-> InChannel %d: 0x%04x=%dV\n", i*2, val, (val * 4000) / 0x7fff);
if ((val < ((volt * 0x7fff) / 40) - ERROR_DELTA) ||
(val > ((volt * 0x7fff) / 40) + ERROR_DELTA)) {
@@ -284,7 +283,7 @@ int do_anatest(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
((volt * 0x7fff) / 40) + ERROR_DELTA);
return -1;
}
- val = in[i*2+1].val;
+ val = in_be16((void *)&(in[i*2+1].val));
printf("-> InChannel %d: 0x%04x=%dV\n", i*2+1, val, (val * 4000) / 0x7fff);
if ((val < ((volt * 0x7fff) / 40) - ERROR_DELTA) ||
(val > ((volt * 0x7fff) / 40) + ERROR_DELTA)) {
@@ -295,9 +294,9 @@ int do_anatest(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
volt = 5;
printf("Setting Channel %d to %dV...\n", i, volt);
- out[i].val = (volt * 0x7fff) / 10;
+ out_be16((void *)&(out[i].val), (volt * 0x7fff) / 10);
udelay(10000);
- val = in[i*2].val;
+ val = in_be16((void *)&(in[i*2].val));
printf("-> InChannel %d: 0x%04x=%dV\n", i*2, val, (val * 4000) / 0x7fff);
if ((val < ((volt * 0x7fff) / 40) - ERROR_DELTA) ||
(val > ((volt * 0x7fff) / 40) + ERROR_DELTA)) {
@@ -305,7 +304,7 @@ int do_anatest(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
((volt * 0x7fff) / 40) + ERROR_DELTA);
return -1;
}
- val = in[i*2+1].val;
+ val = in_be16((void *)&(in[i*2+1].val));
printf("-> InChannel %d: 0x%04x=%dV\n", i*2+1, val, (val * 4000) / 0x7fff);
if ((val < ((volt * 0x7fff) / 40) - ERROR_DELTA) ||
(val > ((volt * 0x7fff) / 40) + ERROR_DELTA)) {
@@ -316,9 +315,9 @@ int do_anatest(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
volt = 10;
printf("Setting Channel %d to %dV...\n", i, volt);
- out[i].val = (volt * 0x7fff) / 10;
+ out_be16((void *)&(out[i].val), (volt * 0x7fff) / 10);
udelay(10000);
- val = in[i*2].val;
+ val = in_be16((void *)&(in[i*2].val));
printf("-> InChannel %d: 0x%04x=%dV\n", i*2, val, (val * 4000) / 0x7fff);
if ((val < ((volt * 0x7fff) / 40) - ERROR_DELTA) ||
(val > ((volt * 0x7fff) / 40) + ERROR_DELTA)) {
@@ -326,7 +325,7 @@ int do_anatest(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
((volt * 0x7fff) / 40) + ERROR_DELTA);
return -1;
}
- val = in[i*2+1].val;
+ val = in_be16((void *)&(in[i*2+1].val));
printf("-> InChannel %d: 0x%04x=%dV\n", i*2+1, val, (val * 4000) / 0x7fff);
if ((val < ((volt * 0x7fff) / 40) - ERROR_DELTA) ||
(val > ((volt * 0x7fff) / 40) + ERROR_DELTA)) {
@@ -350,28 +349,27 @@ int counter = 0;
void cyclicInt(void *ptr)
{
- *(ushort *)0xf03000e8 = 0x0800; /* ack int */
+ out_be16((void *)0xf03000e8, 0x0800); /* ack int */
counter++;
}
int do_inctest(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
- volatile uchar *digout = (volatile uchar *)0xf03000b4;
- volatile ulong *incin;
+ ulong *incin;
int i;
- incin = (volatile ulong *)0xf0300040;
+ incin = (ulong *)0xf0300040;
/*
* Clear inc counter
*/
- incin[0] = 0;
- incin[1] = 0;
- incin[2] = 0;
- incin[3] = 0;
+ out_be32((void *)&incin[0], 0);
+ out_be32((void *)&incin[1], 0);
+ out_be32((void *)&incin[2], 0);
+ out_be32((void *)&incin[3], 0);
- incin = (volatile ulong *)0xf0300050;
+ incin = (ulong *)0xf0300050;
/*
* Inc a little
@@ -379,28 +377,29 @@ int do_inctest(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
for (i=0; i<10000; i++) {
switch (i & 0x03) {
case 0:
- *digout = 0x02;
+ out_8(DIGEN, 0x02);
break;
case 1:
- *digout = 0x03;
+ out_8(DIGEN, 0x03);
break;
case 2:
- *digout = 0x01;
+ out_8(DIGEN, 0x01);
break;
case 3:
- *digout = 0x00;
+ out_8(DIGEN, 0x00);
break;
}
udelay(10);
}
- printf("Inc 0 = %ld\n", incin[0]);
- printf("Inc 1 = %ld\n", incin[1]);
- printf("Inc 2 = %ld\n", incin[2]);
- printf("Inc 3 = %ld\n", incin[3]);
+ printf("Inc 0 = %d\n", in_be32((void *)&incin[0]));
+ printf("Inc 1 = %d\n", in_be32((void *)&incin[1]));
+ printf("Inc 2 = %d\n", in_be32((void *)&incin[2]));
+ printf("Inc 3 = %d\n", in_be32((void *)&incin[3]));
- *(ushort *)0xf03000e0 = 0x0c80-1; /* set counter */
- *(ushort *)0xf03000ec |= 0x0800; /* enable int */
+ out_be16((void *)0xf03000e0, 0x0c80-1); /* set counter */
+ out_be16((void *)0xf03000ec,
+ in_be16((void *)0xf03000ec) | 0x0800); /* enable int */
irq_install_handler (30, (interrupt_handler_t *) cyclicInt, NULL);
printf("counter=%d\n", counter);
diff --git a/board/esd/ar405/u-boot.lds b/board/esd/ar405/u-boot.lds
index 2c1cf92..0221e30 100644
--- a/board/esd/ar405/u-boot.lds
+++ b/board/esd/ar405/u-boot.lds
@@ -57,35 +57,7 @@ SECTIONS
.plt : { *(.plt) }
.text :
{
- /* WARNING - the following is hand-optimized to fit within */
- /* the sector layout of our flash chips! XXX FIXME XXX */
-
cpu/ppc4xx/start.o (.text)
- cpu/ppc4xx/traps.o (.text)
- cpu/ppc4xx/interrupts.o (.text)
- cpu/ppc4xx/4xx_uart.o (.text)
- cpu/ppc4xx/cpu_init.o (.text)
- cpu/ppc4xx/speed.o (.text)
- drivers/net/4xx_enet.o (.text)
- common/dlmalloc.o (.text)
- lib_generic/crc32.o (.text)
- lib_ppc/extable.o (.text)
- lib_ppc/board.o (.text)
- lib_generic/zlib.o (.text)
-
- common/cmd_boot.o (.text)
- common/cmd_bootm.o (.text)
- common/cmd_flash.o (.text)
- common/cmd_mem.o (.text)
- common/cmd_nvedit.o (.text)
- common/console.o (.text)
- common/main.o (.text)
-
-/*
- . = DEFINED(env_offset) ? env_offset : .;
- common/env_embedded.o (.ppcenv)
-*/
- common/env_embedded.o (.text)
*(.text)
*(.fixup)
@@ -95,10 +67,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/ash405/ash405.c b/board/esd/ash405/ash405.c
index dd1e2ec..074fe08 100644
--- a/board/esd/ash405/ash405.c
+++ b/board/esd/ash405/ash405.c
@@ -84,10 +84,6 @@ int board_early_init_f (void)
int misc_init_r (void)
{
- volatile unsigned char *duart0_mcr = (unsigned char *)((ulong)DUART0_BA + 4);
- volatile unsigned char *duart1_mcr = (unsigned char *)((ulong)DUART1_BA + 4);
- volatile unsigned char *duart2_mcr = (unsigned char *)((ulong)DUART2_BA + 4);
- volatile unsigned char *duart3_mcr = (unsigned char *)((ulong)DUART3_BA + 4);
unsigned char *dst;
ulong len = sizeof(fpgadata);
int status;
@@ -165,10 +161,10 @@ int misc_init_r (void)
/*
* Enable interrupts in exar duart mcr[3]
*/
- *duart0_mcr = 0x08;
- *duart1_mcr = 0x08;
- *duart2_mcr = 0x08;
- *duart3_mcr = 0x08;
+ out_8((void *)(DUART0_BA + 4), 0x08);
+ out_8((void *)(DUART1_BA + 4), 0x08);
+ out_8((void *)(DUART2_BA + 4), 0x08);
+ out_8((void *)(DUART3_BA + 4), 0x08);
return (0);
}
diff --git a/board/esd/ash405/u-boot.lds b/board/esd/ash405/u-boot.lds
index e2e2512..005957e 100644
--- a/board/esd/ash405/u-boot.lds
+++ b/board/esd/ash405/u-boot.lds
@@ -57,22 +57,7 @@ SECTIONS
.plt : { *(.plt) }
.text :
{
- /* WARNING - the following is hand-optimized to fit within */
- /* the sector layout of our flash chips! XXX FIXME XXX */
-
cpu/ppc4xx/start.o (.text)
- cpu/ppc4xx/traps.o (.text)
- cpu/ppc4xx/interrupts.o (.text)
- cpu/ppc4xx/4xx_uart.o (.text)
- cpu/ppc4xx/cpu_init.o (.text)
- cpu/ppc4xx/speed.o (.text)
- common/dlmalloc.o (.text)
- lib_generic/crc32.o (.text)
- lib_ppc/extable.o (.text)
- lib_generic/zlib.o (.text)
-
-/* . = env_offset;*/
-/* common/env_embedded.o(.text)*/
*(.text)
*(.fixup)
@@ -82,10 +67,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/canbt/canbt.c b/board/esd/canbt/canbt.c
index 30fa605..2fe6b7b 100644
--- a/board/esd/canbt/canbt.c
+++ b/board/esd/canbt/canbt.c
@@ -24,6 +24,7 @@
#include <common.h>
#include "canbt.h"
#include <asm/processor.h>
+#include <asm/io.h>
#include <command.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -117,9 +118,9 @@ int board_early_init_f (void)
/*
* Setup port pins for normal operation
*/
- out32 (GPIO0_ODR, 0x00000000); /* no open drain pins */
- out32 (GPIO0_TCR, 0x07038100); /* setup for output */
- out32 (GPIO0_OR, 0x07030100); /* set output pins to high (default) */
+ out_be32 ((void *)GPIO0_ODR, 0x00000000); /* no open drain pins */
+ out_be32 ((void *)GPIO0_TCR, 0x07038100); /* setup for output */
+ out_be32 ((void *)GPIO0_OR, 0x07030100); /* set output pins to high (default) */
/*
* IRQ 0-15 405GP internally generated; active high; level sensitive
diff --git a/board/esd/canbt/u-boot.lds b/board/esd/canbt/u-boot.lds
index 74280e6..0221e30 100644
--- a/board/esd/canbt/u-boot.lds
+++ b/board/esd/canbt/u-boot.lds
@@ -57,33 +57,7 @@ SECTIONS
.plt : { *(.plt) }
.text :
{
- /* WARNING - the following is hand-optimized to fit within */
- /* the sector layout of our flash chips! XXX FIXME XXX */
-
cpu/ppc4xx/start.o (.text)
- cpu/ppc4xx/traps.o (.text)
- cpu/ppc4xx/interrupts.o (.text)
- cpu/ppc4xx/4xx_uart.o (.text)
- cpu/ppc4xx/cpu_init.o (.text)
- cpu/ppc4xx/speed.o (.text)
- common/dlmalloc.o (.text)
- lib_ppc/extable.o (.text)
- lib_ppc/board.o (.text)
- lib_generic/zlib.o (.text)
- lib_generic/crc32.o (.text)
-
- common/cmd_boot.o (.text)
- common/cmd_bootm.o (.text)
- common/cmd_flash.o (.text)
- common/cmd_mem.o (.text)
- common/cmd_nvedit.o (.text)
- common/console.o (.text)
- common/main.o (.text)
- net/net.o (.text)
-
-/* . = env_offset;
- common/env_embedded.o (.text)
-*/
*(.text)
*(.fixup)
@@ -93,10 +67,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/cms700/cms700.c b/board/esd/cms700/cms700.c
index d0ee193..9a522b2 100644
--- a/board/esd/cms700/cms700.c
+++ b/board/esd/cms700/cms700.c
@@ -95,14 +95,12 @@ int misc_init_r (void)
/*
* Check Board Identity:
*/
-
+#define LED_REG (CONFIG_SYS_PLD_BASE + 0x1000)
int checkboard (void)
{
char str[64];
int flashcnt;
int delay;
- volatile unsigned char *led_reg = (unsigned char *)((ulong)CONFIG_SYS_PLD_BASE + 0x1000);
- volatile unsigned char *ver_reg = (unsigned char *)((ulong)CONFIG_SYS_PLD_BASE + 0x1001);
puts ("Board: ");
@@ -112,20 +110,21 @@ int checkboard (void)
puts(str);
}
- printf(" (PLD-Version=%02d)\n", *ver_reg);
+ printf(" (PLD-Version=%02d)\n",
+ in_8((void *)(CONFIG_SYS_PLD_BASE + 0x1001)));
/*
* Flash LEDs
*/
for (flashcnt = 0; flashcnt < 3; flashcnt++) {
- *led_reg = 0x00; /* LEDs off */
+ out_8((void *)LED_REG, 0x00); /* LEDs off */
for (delay = 0; delay < 100; delay++)
udelay(1000);
- *led_reg = 0x0f; /* LEDs on */
+ out_8((void *)LED_REG, 0x0f); /* LEDs on */
for (delay = 0; delay < 50; delay++)
udelay(1000);
}
- *led_reg = 0x70;
+ out_8((void *)LED_REG, 0x70);
return 0;
}
diff --git a/board/esd/cms700/u-boot.lds b/board/esd/cms700/u-boot.lds
index 9697cc6..8c01016 100644
--- a/board/esd/cms700/u-boot.lds
+++ b/board/esd/cms700/u-boot.lds
@@ -57,22 +57,7 @@ SECTIONS
.plt : { *(.plt) }
.text :
{
- /* WARNING - the following is hand-optimized to fit within */
- /* the sector layout of our flash chips! XXX FIXME XXX */
-
cpu/ppc4xx/start.o (.text)
- cpu/ppc4xx/traps.o (.text)
- cpu/ppc4xx/interrupts.o (.text)
- cpu/ppc4xx/4xx_uart.o (.text)
- cpu/ppc4xx/cpu_init.o (.text)
- cpu/ppc4xx/speed.o (.text)
- common/dlmalloc.o (.text)
- lib_generic/crc32.o (.text)
- lib_ppc/extable.o (.text)
- lib_generic/zlib.o (.text)
-
-/* . = env_offset;*/
-/* common/env_embedded.o(.text)*/
*(.text)
*(.fixup)
@@ -82,10 +67,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/common/fpga.c b/board/esd/common/fpga.c
index 5232ddd..62c3243 100644
--- a/board/esd/common/fpga.c
+++ b/board/esd/common/fpga.c
@@ -24,6 +24,7 @@
#include <common.h>
#include <asm/processor.h>
+#include <asm/io.h>
#include <command.h>
/* ------------------------------------------------------------------------- */
@@ -55,7 +56,7 @@
#define ERROR_FPGA_PRG_DONE -3 /* Timeout after programming */
#ifndef SET_FPGA
-# define SET_FPGA(data) out32(GPIO0_OR, data)
+# define SET_FPGA(data) out_be32((void *)GPIO0_OR, data)
#endif
#ifdef FPGA_PROG_ACTIVE_HIGH
@@ -85,10 +86,10 @@
SET_FPGA(FPGA_PRG_HIGH | FPGA_CLK_HIGH | FPGA_DATA_HIGH);} /* set data to 1 */
#ifndef FPGA_DONE_STATE
-# define FPGA_DONE_STATE (in32(GPIO0_IR) & FPGA_DONE)
+# define FPGA_DONE_STATE (in_be32((void *)GPIO0_IR) & FPGA_DONE)
#endif
#ifndef FPGA_INIT_STATE
-# define FPGA_INIT_STATE (in32(GPIO0_IR) & FPGA_INIT)
+# define FPGA_INIT_STATE (in_be32((void *)GPIO0_IR) & FPGA_INIT)
#endif
@@ -139,8 +140,11 @@ static int fpga_boot (const unsigned char *fpgadata, int size)
* Setup port pins for fpga programming
*/
#ifndef CONFIG_M5249
- out32 (GPIO0_ODR, 0x00000000); /* no open drain pins */
- out32 (GPIO0_TCR, in32 (GPIO0_TCR) | FPGA_PRG | FPGA_CLK | FPGA_DATA); /* setup for output */
+ out_be32 ((void *)GPIO0_ODR, 0x00000000); /* no open drain pins */
+ /* setup for output */
+ out_be32 ((void *)GPIO0_TCR,
+ in_be32 ((void *)GPIO0_TCR) |
+ FPGA_PRG | FPGA_CLK | FPGA_DATA);
#endif
SET_FPGA (FPGA_PRG_HIGH | FPGA_CLK_HIGH | FPGA_DATA_HIGH); /* set pins to high */
diff --git a/board/esd/common/lcd.h b/board/esd/common/lcd.h
index 3169e6b..01f6019 100644
--- a/board/esd/common/lcd.h
+++ b/board/esd/common/lcd.h
@@ -40,13 +40,13 @@
#define TRUE (!FALSE)
#endif
-#define S1D_WRITE_PALETTE(p,i,r,g,b) \
- { \
- ((volatile uchar*)(p))[palette_index] = (uchar)(i); \
- ((volatile uchar*)(p))[palette_value] = (uchar)(r); \
- ((volatile uchar*)(p))[palette_value] = (uchar)(g); \
- ((volatile uchar*)(p))[palette_value] = (uchar)(b); \
- }
+#define S1D_WRITE_PALETTE(p,i,r,g,b) \
+ { \
+ out_8(&((uchar*)(p))[palette_index], (uchar)(i)); \
+ out_8(&((uchar*)(p))[palette_index], (uchar)(r)); \
+ out_8(&((uchar*)(p))[palette_index], (uchar)(g)); \
+ out_8(&((uchar*)(p))[palette_index], (uchar)(b)); \
+ }
typedef struct
{
diff --git a/board/esd/common/xilinx_jtag/ports.c b/board/esd/common/xilinx_jtag/ports.c
index 3ad94a5..ac0d7ac 100644
--- a/board/esd/common/xilinx_jtag/ports.c
+++ b/board/esd/common/xilinx_jtag/ports.c
@@ -32,6 +32,7 @@
#include <common.h>
#include <asm/processor.h>
+#include <asm/io.h>
#include "ports.h"
@@ -68,7 +69,7 @@ void setPort(short p,short val)
} else {
output &= ~JTAG_TCK;
}
- out32(GPIO0_OR, output);
+ out_be32((void *)GPIO0_OR, output);
}
}
@@ -98,7 +99,7 @@ unsigned char readTDOBit(void)
{
unsigned long inputs;
- inputs = in32(GPIO0_IR);
+ inputs = in_be32((void *)GPIO0_IR);
if (inputs & JTAG_TDO)
return 1;
else
diff --git a/board/esd/cpci2dp/cpci2dp.c b/board/esd/cpci2dp/cpci2dp.c
index 517b174..aba240f 100644
--- a/board/esd/cpci2dp/cpci2dp.c
+++ b/board/esd/cpci2dp/cpci2dp.c
@@ -23,6 +23,7 @@
#include <common.h>
#include <asm/processor.h>
+#include <asm/io.h>
#include <command.h>
#include <malloc.h>
@@ -36,12 +37,14 @@ int board_early_init_f (void)
* Setup GPIO pins
*/
cntrl0Reg = mfdcr(cntrl0);
- mtdcr(cntrl0, cntrl0Reg | ((CONFIG_SYS_EEPROM_WP | CONFIG_SYS_PB_LED | CONFIG_SYS_SELF_RST | CONFIG_SYS_INTA_FAKE) << 5));
+ mtdcr(cntrl0, cntrl0Reg |
+ ((CONFIG_SYS_EEPROM_WP | CONFIG_SYS_PB_LED |
+ CONFIG_SYS_SELF_RST | CONFIG_SYS_INTA_FAKE) << 5));
/* set output pins to high */
- out32(GPIO0_OR, CONFIG_SYS_EEPROM_WP);
+ out_be32((void *)GPIO0_OR, CONFIG_SYS_EEPROM_WP);
/* setup for output (LED=off) */
- out32(GPIO0_TCR, CONFIG_SYS_EEPROM_WP | CONFIG_SYS_PB_LED);
+ out_be32((void *)GPIO0_TCR, CONFIG_SYS_EEPROM_WP | CONFIG_SYS_PB_LED);
/*
* IRQ 0-15 405GP internally generated; active high; level sensitive
@@ -124,17 +127,20 @@ int eeprom_write_enable (unsigned dev_addr, int state) {
switch (state) {
case 1:
/* Enable write access, clear bit GPIO_SINT2. */
- out32(GPIO0_OR, in32(GPIO0_OR) & ~CONFIG_SYS_EEPROM_WP);
+ out_be32((void *)GPIO0_OR,
+ in_be32((void *)GPIO0_OR) & ~CONFIG_SYS_EEPROM_WP);
state = 0;
break;
case 0:
/* Disable write access, set bit GPIO_SINT2. */
- out32(GPIO0_OR, in32(GPIO0_OR) | CONFIG_SYS_EEPROM_WP);
+ out_be32((void *)GPIO0_OR,
+ in_be32((void *)GPIO0_OR) | CONFIG_SYS_EEPROM_WP);
state = 0;
break;
default:
/* Read current status back. */
- state = (0 == (in32(GPIO0_OR) & CONFIG_SYS_EEPROM_WP));
+ state = (0 == (in_be32((void *)GPIO0_OR) &
+ CONFIG_SYS_EEPROM_WP));
break;
}
}
diff --git a/board/esd/cpci2dp/u-boot.lds b/board/esd/cpci2dp/u-boot.lds
index 9697cc6..8c01016 100644
--- a/board/esd/cpci2dp/u-boot.lds
+++ b/board/esd/cpci2dp/u-boot.lds
@@ -57,22 +57,7 @@ SECTIONS
.plt : { *(.plt) }
.text :
{
- /* WARNING - the following is hand-optimized to fit within */
- /* the sector layout of our flash chips! XXX FIXME XXX */
-
cpu/ppc4xx/start.o (.text)
- cpu/ppc4xx/traps.o (.text)
- cpu/ppc4xx/interrupts.o (.text)
- cpu/ppc4xx/4xx_uart.o (.text)
- cpu/ppc4xx/cpu_init.o (.text)
- cpu/ppc4xx/speed.o (.text)
- common/dlmalloc.o (.text)
- lib_generic/crc32.o (.text)
- lib_ppc/extable.o (.text)
- lib_generic/zlib.o (.text)
-
-/* . = env_offset;*/
-/* common/env_embedded.o(.text)*/
*(.text)
*(.fixup)
@@ -82,10 +67,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/cpci405/cpci405.c b/board/esd/cpci405/cpci405.c
index 0aca825..ccbe245 100644
--- a/board/esd/cpci405/cpci405.c
+++ b/board/esd/cpci405/cpci405.c
@@ -111,10 +111,10 @@ int board_early_init_f(void)
* First pull fpga-prg pin low,
* to disable fpga logic (on version 2 board)
*/
- out32(GPIO0_ODR, 0x00000000); /* no open drain pins */
- out32(GPIO0_TCR, CONFIG_SYS_FPGA_PRG); /* setup for output */
- out32(GPIO0_OR, CONFIG_SYS_FPGA_PRG); /* set output pins to high */
- out32(GPIO0_OR, 0); /* pull prg low */
+ out_be32((void *)GPIO0_ODR, 0x00000000); /* no open drain pins */
+ out_be32((void *)GPIO0_TCR, CONFIG_SYS_FPGA_PRG); /* setup for output */
+ out_be32((void *)GPIO0_OR, CONFIG_SYS_FPGA_PRG); /* set output pins to high */
+ out_be32((void *)GPIO0_OR, 0); /* pull prg low */
/*
* Boot onboard FPGA
diff --git a/board/esd/cpci405/u-boot.lds b/board/esd/cpci405/u-boot.lds
index 5d59761..8c01016 100644
--- a/board/esd/cpci405/u-boot.lds
+++ b/board/esd/cpci405/u-boot.lds
@@ -67,10 +67,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/cpci750/u-boot.lds b/board/esd/cpci750/u-boot.lds
index ff2d8b7..632921a 100644
--- a/board/esd/cpci750/u-boot.lds
+++ b/board/esd/cpci750/u-boot.lds
@@ -70,10 +70,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/cpciiser4/cpciiser4.c b/board/esd/cpciiser4/cpciiser4.c
index b5d2543..6e97392 100644
--- a/board/esd/cpciiser4/cpciiser4.c
+++ b/board/esd/cpciiser4/cpciiser4.c
@@ -58,7 +58,6 @@ const unsigned char fpgadata[] = {
int board_early_init_f (void)
{
int index, len, i;
- volatile unsigned char dummy;
int status;
#ifdef FPGA_DEBUG
@@ -116,7 +115,7 @@ int board_early_init_f (void)
/*
* Init FPGA via RESET (read access on CS3)
*/
- dummy = *(unsigned char *) 0xf0200000;
+ in_8((void *)0xf0200000);
/*
* IRQ 0-15 405GP internally generated; active high; level sensitive
diff --git a/board/esd/cpciiser4/u-boot.lds b/board/esd/cpciiser4/u-boot.lds
index 9697cc6..8c01016 100644
--- a/board/esd/cpciiser4/u-boot.lds
+++ b/board/esd/cpciiser4/u-boot.lds
@@ -57,22 +57,7 @@ SECTIONS
.plt : { *(.plt) }
.text :
{
- /* WARNING - the following is hand-optimized to fit within */
- /* the sector layout of our flash chips! XXX FIXME XXX */
-
cpu/ppc4xx/start.o (.text)
- cpu/ppc4xx/traps.o (.text)
- cpu/ppc4xx/interrupts.o (.text)
- cpu/ppc4xx/4xx_uart.o (.text)
- cpu/ppc4xx/cpu_init.o (.text)
- cpu/ppc4xx/speed.o (.text)
- common/dlmalloc.o (.text)
- lib_generic/crc32.o (.text)
- lib_ppc/extable.o (.text)
- lib_generic/zlib.o (.text)
-
-/* . = env_offset;*/
-/* common/env_embedded.o(.text)*/
*(.text)
*(.fixup)
@@ -82,10 +67,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/dasa_sim/cmd_dasa_sim.c b/board/esd/dasa_sim/cmd_dasa_sim.c
index f405be9..0310c47 100644
--- a/board/esd/dasa_sim/cmd_dasa_sim.c
+++ b/board/esd/dasa_sim/cmd_dasa_sim.c
@@ -25,6 +25,7 @@
#include <common.h>
#include <command.h>
#include <pci.h>
+#include <asm/io.h>
#define OK 0
#define ERROR (-1)
@@ -136,8 +137,8 @@ static void updatePci9054 (void)
/*
* Set EEPROM write-protect register to 0
*/
- out32 (pci9054_iobase + 0x0c,
- in32 (pci9054_iobase + 0x0c) & 0xffff00ff);
+ out_be32 ((void *)(pci9054_iobase + 0x0c),
+ in_be32 ((void *)(pci9054_iobase + 0x0c)) & 0xffff00ff);
/* Long Serial EEPROM Load Registers... */
val = PciEepromWriteLongVPD (0x00, 0x905410b5);
@@ -190,8 +191,8 @@ static void clearPci9054 (void)
/*
* Set EEPROM write-protect register to 0
*/
- out32 (pci9054_iobase + 0x0c,
- in32 (pci9054_iobase + 0x0c) & 0xffff00ff);
+ out_be32 ((void *)(pci9054_iobase + 0x0c),
+ in_be32 ((void *)(pci9054_iobase + 0x0c)) & 0xffff00ff);
/* Long Serial EEPROM Load Registers... */
val = PciEepromWriteLongVPD (0x00, 0xffffffff);
diff --git a/board/esd/dasa_sim/config.mk b/board/esd/dasa_sim/config.mk
index 747f29f..5d612d2 100644
--- a/board/esd/dasa_sim/config.mk
+++ b/board/esd/dasa_sim/config.mk
@@ -20,14 +20,5 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA 02111-1307 USA
#
+TEXT_BASE = 0xFFFC0000
-#
-# esd ADCIOP boards
-#
-
-# FLASH:
-#TEXT_BASE = 0xFFFE0000
-TEXT_BASE = 0xFFFD0000
-
-# SDRAM:
-#TEXT_BASE = 0x00FE0000
diff --git a/board/esd/dasa_sim/dasa_sim.c b/board/esd/dasa_sim/dasa_sim.c
index 47d6bb3..127374b 100644
--- a/board/esd/dasa_sim/dasa_sim.c
+++ b/board/esd/dasa_sim/dasa_sim.c
@@ -74,7 +74,8 @@ static int fpgaBoot (void)
#ifdef FPGA_DEBUG
printf ("%s\n",
- ((in32 (0x50000084) & 0x00010000) == 0) ? "NOT DONE" : "DONE");
+ ((in_be32 ((void *)0x50000084) & 0x00010000) == 0) ?
+ "NOT DONE" : "DONE");
#endif
/* init fpga by asserting and deasserting PROGRAM* (USER2)... */
@@ -86,7 +87,8 @@ static int fpgaBoot (void)
#ifdef FPGA_DEBUG
printf ("%s\n",
- ((in32 (0x50000084) & 0x00010000) == 0) ? "NOT DONE" : "DONE");
+ ((in_be32 ((void *)0x50000084) & 0x00010000) == 0) ?
+ "NOT DONE" : "DONE");
#endif
/* cs1: disable burst, disable ready */
@@ -109,7 +111,8 @@ static int fpgaBoot (void)
#ifdef FPGA_DEBUG
printf ("%s\n",
- ((in32 (0x50000084) & 0x00010000) == 0) ? "NOT DONE" : "DONE");
+ ((in_be32 ((void *)0x50000084) & 0x00010000) == 0) ?
+ "NOT DONE" : "DONE");
#endif
/* set cs1 to 32 bit data-width, disable burst, enable ready */
@@ -125,7 +128,8 @@ static int fpgaBoot (void)
#ifdef FPGA_DEBUG
printf ("%s\n",
- ((in32 (0x50000084) & 0x00010000) == 0) ? "NOT DONE" : "DONE");
+ ((in_be32 ((void *)0x50000084) & 0x00010000) == 0) ?
+ "NOT DONE" : "DONE");
#endif
/* wait for 30 ms... */
diff --git a/board/esd/dasa_sim/eeprom.c b/board/esd/dasa_sim/eeprom.c
index 1b4c7b3..aa6f52c 100644
--- a/board/esd/dasa_sim/eeprom.c
+++ b/board/esd/dasa_sim/eeprom.c
@@ -24,7 +24,7 @@
#include <common.h>
#include <command.h>
-
+#include <asm/io.h>
#define EEPROM_CAP 0x50000358
#define EEPROM_DATA 0x5000035c
@@ -33,23 +33,23 @@
unsigned int eepromReadLong(int offs)
{
unsigned int value;
- volatile unsigned short ret;
+ unsigned short ret;
int count;
- *(unsigned short *)EEPROM_CAP = offs;
+ out_be16((void *)EEPROM_CAP, offs);
count = 0;
for (;;)
{
count++;
- ret = *(unsigned short *)EEPROM_CAP;
+ ret = in_be16((void *)EEPROM_CAP);
if ((ret & 0x8000) != 0)
break;
}
- value = *(unsigned long *)EEPROM_DATA;
+ value = in_be32((void *)EEPROM_DATA);
return value;
}
@@ -69,18 +69,18 @@ unsigned char eepromReadByte(int offs)
void eepromWriteLong(int offs, unsigned int value)
{
- volatile unsigned short ret;
+ unsigned short ret;
int count;
count = 0;
- *(unsigned long *)EEPROM_DATA = value;
- *(unsigned short *)EEPROM_CAP = 0x8000 + offs;
+ out_be32((void *)EEPROM_DATA, value);
+ out_be16((void *)EEPROM_CAP, 0x8000 + offs);
for (;;)
{
count++;
- ret = *(unsigned short *)EEPROM_CAP;
+ ret = in_be16((void *)EEPROM_CAP);
if ((ret & 0x8000) == 0)
break;
diff --git a/board/esd/dasa_sim/u-boot.lds b/board/esd/dasa_sim/u-boot.lds
index 6acf7b8..77674b5 100644
--- a/board/esd/dasa_sim/u-boot.lds
+++ b/board/esd/dasa_sim/u-boot.lds
@@ -57,33 +57,7 @@ SECTIONS
.plt : { *(.plt) }
.text :
{
- /* WARNING - the following is hand-optimized to fit within */
- /* the sector layout of our flash chips! XXX FIXME XXX */
-
cpu/ppc4xx/start.o (.text)
- cpu/ppc4xx/traps.o (.text)
- cpu/ppc4xx/interrupts.o (.text)
- cpu/ppc4xx/iop480_uart.o (.text)
- cpu/ppc4xx/cpu_init.o (.text)
- cpu/ppc4xx/speed.o (.text)
- common/dlmalloc.o (.text)
- lib_ppc/extable.o (.text)
- lib_ppc/board.o (.text)
- lib_generic/zlib.o (.text)
- lib_generic/crc32.o (.text)
-
- common/cmd_boot.o (.text)
- common/cmd_bootm.o (.text)
- common/cmd_flash.o (.text)
- common/cmd_mem.o (.text)
- common/cmd_nvedit.o (.text)
- common/console.o (.text)
- common/main.o (.text)
-
- board/esd/dasa_sim/flash.o (.text)
- common/cmd_nvedit.o (.text)
- board/esd/dasa_sim/cmd_dasa_sim.o (.text)
- net/bootp.o (.text)
. = env_offset;
common/env_embedded.o(.text)
@@ -96,10 +70,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/dp405/dp405.c b/board/esd/dp405/dp405.c
index eb001da..c32c7c7 100644
--- a/board/esd/dp405/dp405.c
+++ b/board/esd/dp405/dp405.c
@@ -23,6 +23,7 @@
#include <common.h>
#include <asm/processor.h>
+#include <asm/io.h>
#include <command.h>
#include <malloc.h>
@@ -66,9 +67,11 @@ int board_early_init_f (void)
/*
* Reset CPLD via GPIO13 (CS4) pin
*/
- out32(GPIO0_OR, in32(GPIO0_OR) & ~(0x80000000 >> 13));
+ out_be32((void *)GPIO0_OR,
+ in_be32((void *)GPIO0_OR) & ~(0x80000000 >> 13));
udelay(1000); /* wait 1ms */
- out32(GPIO0_OR, in32(GPIO0_OR) | (0x80000000 >> 13));
+ out_be32((void *)GPIO0_OR,
+ in_be32((void *)GPIO0_OR) | (0x80000000 >> 13));
udelay(1000); /* wait 1ms */
return 0;
@@ -104,9 +107,10 @@ int checkboard (void)
puts(str);
}
- id1 = trans[(~(in32(GPIO0_IR) >> 5)) & 0x0000000f];
- id2 = trans[(~(in32(GPIO0_IR) >> 9)) & 0x0000000f];
- printf(" (ID=0x%1X%1X, PLD=0x%02X)\n", id2, id1, in8(0xf0001000));
+ id1 = trans[(~(in_be32((void *)GPIO0_IR) >> 5)) & 0x0000000f];
+ id2 = trans[(~(in_be32((void *)GPIO0_IR) >> 9)) & 0x0000000f];
+ printf(" (ID=0x%1X%1X, PLD=0x%02X)\n",
+ id2, id1, in_8((void *)0xf0001000));
return 0;
}
diff --git a/board/esd/dp405/u-boot.lds b/board/esd/dp405/u-boot.lds
index d8fbea3..8c01016 100644
--- a/board/esd/dp405/u-boot.lds
+++ b/board/esd/dp405/u-boot.lds
@@ -57,23 +57,7 @@ SECTIONS
.plt : { *(.plt) }
.text :
{
- /* WARNING - the following is hand-optimized to fit within */
- /* the sector layout of our flash chips! XXX FIXME XXX */
-
cpu/ppc4xx/start.o (.text)
- cpu/ppc4xx/traps.o (.text)
- cpu/ppc4xx/interrupts.o (.text)
- cpu/ppc4xx/4xx_uart.o (.text)
- cpu/ppc4xx/cpu_init.o (.text)
- cpu/ppc4xx/speed.o (.text)
- drivers/net/4xx_enet.o (.text)
- common/dlmalloc.o (.text)
- lib_generic/crc32.o (.text)
- lib_ppc/extable.o (.text)
- lib_generic/zlib.o (.text)
-
-/* . = env_offset;*/
-/* common/env_embedded.o(.text)*/
*(.text)
*(.fixup)
@@ -83,10 +67,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/du405/du405.c b/board/esd/du405/du405.c
index 8a87d55..8e9ac28 100644
--- a/board/esd/du405/du405.c
+++ b/board/esd/du405/du405.c
@@ -188,13 +188,19 @@ int checkboard (void)
/*
* Reset external DUART via FPGA
*/
- *(volatile unsigned char *) FPGA_MODE_REG = 0xff; /* reset high active */
- *(volatile unsigned char *) FPGA_MODE_REG = 0x00; /* low again */
+ out_8((void *)FPGA_MODE_REG, 0xff); /* reset high active */
+ out_8((void *)FPGA_MODE_REG, 0x00); /* low again */
+
+ return 0;
+}
+
+void reset_phy(void)
+{
+#if defined(CONFIG_LXT971_NO_SLEEP)
/*
* Disable sleep mode in LXT971
*/
lxt971_no_sleep();
-
- return 0;
+#endif
}
diff --git a/board/esd/du405/u-boot.lds b/board/esd/du405/u-boot.lds
index 858ae61..166d0d1 100644
--- a/board/esd/du405/u-boot.lds
+++ b/board/esd/du405/u-boot.lds
@@ -57,22 +57,7 @@ SECTIONS
.plt : { *(.plt) }
.text :
{
- /* WARNING - the following is hand-optimized to fit within */
- /* the sector layout of our flash chips! XXX FIXME XXX */
-
cpu/ppc4xx/start.o (.text)
- cpu/ppc4xx/traps.o (.text)
- cpu/ppc4xx/interrupts.o (.text)
- cpu/ppc4xx/4xx_uart.o (.text)
- cpu/ppc4xx/cpu_init.o (.text)
- cpu/ppc4xx/speed.o (.text)
- common/dlmalloc.o (.text)
- lib_generic/crc32.o (.text)
- lib_ppc/extable.o (.text)
- lib_generic/zlib.o (.text)
-
-/* . = env_offset;*/
-/* common/env_embedded.o(.text)*/
*(.text)
*(.fixup)
@@ -82,10 +67,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/du440/du440.c b/board/esd/du440/du440.c
index f9b91b5..45dfa6f 100644
--- a/board/esd/du440/du440.c
+++ b/board/esd/du440/du440.c
@@ -310,8 +310,8 @@ int misc_init_r(void)
int pld_revision(void)
{
- out8(CONFIG_SYS_CPLD_BASE, 0x00);
- return (int)(in8(CONFIG_SYS_CPLD_BASE) & CPLD_VERSION_MASK);
+ out_8((void *)CONFIG_SYS_CPLD_BASE, 0x00);
+ return (int)(in_8((void *)CONFIG_SYS_CPLD_BASE) & CPLD_VERSION_MASK);
}
int board_revision(void)
@@ -872,12 +872,12 @@ static int got_pldirq;
static int pld_interrupt(u32 arg)
{
int rc = -1; /* not for us */
- u8 status = in8(CONFIG_SYS_CPLD_BASE);
+ u8 status = in_8((void *)CONFIG_SYS_CPLD_BASE);
/* check for PLD interrupt */
if (status & PWR_INT_FLAG) {
/* reset this int */
- out8(CONFIG_SYS_CPLD_BASE, 0);
+ out_8((void *)CONFIG_SYS_CPLD_BASE, 0);
rc = 0;
got_pldirq = 1; /* trigger backend */
}
@@ -890,7 +890,7 @@ int do_waitpwrirq(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
got_pldirq = 0;
/* clear any pending interrupt */
- out8(CONFIG_SYS_CPLD_BASE, 0);
+ out_8((void *)CONFIG_SYS_CPLD_BASE, 0);
irq_install_handler(CPLD_IRQ,
(interrupt_handler_t *)pld_interrupt, 0);
@@ -906,7 +906,8 @@ int do_waitpwrirq(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
if (got_pldirq) {
printf("Got interrupt!\n");
printf("Power %sready!\n",
- in8(CONFIG_SYS_CPLD_BASE) & PWR_RDY ? "":"NOT ");
+ in_8((void *)CONFIG_SYS_CPLD_BASE) &
+ PWR_RDY ? "":"NOT ");
}
irq_free_handler(CPLD_IRQ);
diff --git a/board/esd/du440/u-boot.lds b/board/esd/du440/u-boot.lds
index 05152b7..7360349 100644
--- a/board/esd/du440/u-boot.lds
+++ b/board/esd/du440/u-boot.lds
@@ -62,9 +62,6 @@ SECTIONS
.plt : { *(.plt) }
.text :
{
- /* WARNING - the following is hand-optimized to fit within */
- /* the sector layout of our flash chips! XXX FIXME XXX */
-
cpu/ppc4xx/start.o (.text)
*(.text)
@@ -75,9 +72,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/hh405/hh405.c b/board/esd/hh405/hh405.c
index ae3bc80..eab952c 100644
--- a/board/esd/hh405/hh405.c
+++ b/board/esd/hh405/hh405.c
@@ -29,6 +29,7 @@
#include <common.h>
#include <asm/processor.h>
+#include <asm/io.h>
#include <command.h>
#include <malloc.h>
#include <pci.h>
@@ -36,6 +37,26 @@
DECLARE_GLOBAL_DATA_PTR;
+/* FPGA internal regs */
+#define FPGA_CTRL ((u16 *)(CONFIG_SYS_FPGA_BASE_ADDR + 0x000))
+#define FPGA_STATUS ((u16 *)(CONFIG_SYS_FPGA_BASE_ADDR + 0x002))
+#define FPGA_CTR ((u16 *)(CONFIG_SYS_FPGA_BASE_ADDR + 0x004))
+#define FPGA_BL ((u16 *)(CONFIG_SYS_FPGA_BASE_ADDR + 0x006))
+
+/* FPGA Control Reg */
+#define FPGA_CTRL_REV0 0x0001
+#define FPGA_CTRL_REV1 0x0002
+#define FPGA_CTRL_VGA0_BL 0x0004
+#define FPGA_CTRL_VGA0_BL_MODE 0x0008
+#define FPGA_CTRL_CF_RESET 0x0040
+#define FPGA_CTRL_PS2_PWR 0x0080
+#define FPGA_CTRL_CF_PWRN 0x0100 /* low active */
+#define FPGA_CTRL_CF_BUS_EN 0x0200
+#define FPGA_CTRL_LCD_CLK 0x7000 /* mask for lcd clock */
+#define FPGA_CTRL_OW_ENABLE 0x8000
+
+#define FPGA_STATUS_CF_DETECT 0x8000
+
#ifdef CONFIG_VIDEO_SM501
#define SWAP32(x) ((((x) & 0x000000ff) << 24) | (((x) & 0x0000ff00) << 8)|\
@@ -297,22 +318,22 @@ int board_revision(void)
/*
* Setup GPIO pins (BLAST/GPIO0 and GPIO9 as GPIO)
*/
- osrh_reg = in32(GPIO0_OSRH);
- isr1h_reg = in32(GPIO0_ISR1H);
- tcr_reg = in32(GPIO0_TCR);
- out32(GPIO0_OSRH, osrh_reg & ~0xC0003000); /* output select */
- out32(GPIO0_ISR1H, isr1h_reg | 0xC0003000); /* input select */
- out32(GPIO0_TCR, tcr_reg & ~0x80400000); /* select input */
+ osrh_reg = in_be32((void *)GPIO0_OSRH);
+ isr1h_reg = in_be32((void *)GPIO0_ISR1H);
+ tcr_reg = in_be32((void *)GPIO0_TCR);
+ out_be32((void *)GPIO0_OSRH, osrh_reg & ~0xC0003000); /* output select */
+ out_be32((void *)GPIO0_ISR1H, isr1h_reg | 0xC0003000); /* input select */
+ out_be32((void *)GPIO0_TCR, tcr_reg & ~0x80400000); /* select input */
udelay(1000); /* wait some time before reading input */
- value = in32(GPIO0_IR) & 0x80400000; /* get config bits */
+ value = in_be32((void *)GPIO0_IR) & 0x80400000; /* get config bits */
/*
* Restore GPIO settings
*/
- out32(GPIO0_OSRH, osrh_reg); /* output select */
- out32(GPIO0_ISR1H, isr1h_reg); /* input select */
- out32(GPIO0_TCR, tcr_reg); /* enable output driver for outputs */
+ out_be32((void *)GPIO0_OSRH, osrh_reg); /* output select */
+ out_be32((void *)GPIO0_ISR1H, isr1h_reg); /* input select */
+ out_be32((void *)GPIO0_TCR, tcr_reg); /* enable output driver for outputs */
if (value & 0x80000000) {
/* Revision 1.0 or 1.1 detected */
@@ -353,7 +374,7 @@ int board_early_init_f (void)
/*
* EBC Configuration Register: set ready timeout to 512 ebc-clks -> ca. 15 us
*/
- mtebc (epcr, 0xa8400000); /* ebc always driven */
+ mtebc(epcr, 0xa8400000); /* ebc always driven */
return 0;
}
@@ -362,27 +383,26 @@ int cf_enable(void)
{
int i;
- volatile unsigned short *fpga_ctrl =
- (unsigned short *)((ulong)CONFIG_SYS_FPGA_BASE_ADDR + CONFIG_SYS_FPGA_CTRL);
- volatile unsigned short *fpga_status =
- (unsigned short *)((ulong)CONFIG_SYS_FPGA_BASE_ADDR + CONFIG_SYS_FPGA_CTRL + 2);
-
if (gd->board_type >= 2) {
- if (*fpga_status & CONFIG_SYS_FPGA_STATUS_CF_DETECT) {
- if (!(*fpga_ctrl & CONFIG_SYS_FPGA_CTRL_CF_BUS_EN)) {
- *fpga_ctrl &= ~CONFIG_SYS_FPGA_CTRL_CF_PWRN;
+ if (in_be16(FPGA_STATUS) & FPGA_STATUS_CF_DETECT) {
+ if (!(in_be16(FPGA_CTRL) & FPGA_CTRL_CF_BUS_EN)) {
+ out_be16(FPGA_CTRL,
+ in_be16(FPGA_CTRL) & ~FPGA_CTRL_CF_PWRN);
for (i=0; i<300; i++)
udelay(1000);
- *fpga_ctrl |= CONFIG_SYS_FPGA_CTRL_CF_BUS_EN;
+ out_be16(FPGA_CTRL,
+ in_be16(FPGA_CTRL) | FPGA_CTRL_CF_BUS_EN);
for (i=0; i<20; i++)
udelay(1000);
}
} else {
- *fpga_ctrl &= ~CONFIG_SYS_FPGA_CTRL_CF_BUS_EN;
- *fpga_ctrl |= CONFIG_SYS_FPGA_CTRL_CF_PWRN;
+ out_be16(FPGA_CTRL,
+ in_be16(FPGA_CTRL) & ~FPGA_CTRL_CF_BUS_EN);
+ out_be16(FPGA_CTRL,
+ in_be16(FPGA_CTRL) | FPGA_CTRL_CF_PWRN);
}
}
@@ -391,12 +411,6 @@ int cf_enable(void)
int misc_init_r (void)
{
- volatile unsigned short *fpga_ctrl =
- (unsigned short *)((ulong)CONFIG_SYS_FPGA_BASE_ADDR + CONFIG_SYS_FPGA_CTRL);
- volatile unsigned short *lcd_contrast =
- (unsigned short *)((ulong)CONFIG_SYS_FPGA_BASE_ADDR + CONFIG_SYS_FPGA_CTRL + 4);
- volatile unsigned short *lcd_backlight =
- (unsigned short *)((ulong)CONFIG_SYS_FPGA_BASE_ADDR + CONFIG_SYS_FPGA_CTRL + 6);
unsigned char *dst;
ulong len = sizeof(fpgadata);
int status;
@@ -460,36 +474,43 @@ int misc_init_r (void)
/*
* Reset FPGA via FPGA_INIT pin
*/
- out32(GPIO0_TCR, in32(GPIO0_TCR) | FPGA_INIT); /* setup FPGA_INIT as output */
- out32(GPIO0_OR, in32(GPIO0_OR) & ~FPGA_INIT); /* reset low */
+ /* setup FPGA_INIT as output */
+ out_be32((void *)GPIO0_TCR,
+ in_be32((void *)GPIO0_TCR) | FPGA_INIT);
+ out_be32((void *)GPIO0_OR,
+ in_be32((void *)GPIO0_OR) & ~FPGA_INIT); /* reset low */
udelay(1000); /* wait 1ms */
- out32(GPIO0_OR, in32(GPIO0_OR) | FPGA_INIT); /* reset high */
+ out_be32((void *)GPIO0_OR,
+ in_be32((void *)GPIO0_OR) | FPGA_INIT); /* reset high */
udelay(1000); /* wait 1ms */
/*
* Write Board revision into FPGA
*/
- *fpga_ctrl |= gd->board_type & 0x0003;
+ out_be16(FPGA_CTRL, in_be16(FPGA_CTRL) | (gd->board_type & 0x0003));
/*
* Setup and enable EEPROM write protection
*/
- out32(GPIO0_OR, in32(GPIO0_OR) | CONFIG_SYS_EEPROM_WP);
+ out_be32((void *)GPIO0_OR,
+ in_be32((void *)GPIO0_OR) | CONFIG_SYS_EEPROM_WP);
/*
* Reset touch-screen controller
*/
- out32(GPIO0_OR, in32(GPIO0_OR) & ~CONFIG_SYS_TOUCH_RST);
+ out_be32((void *)GPIO0_OR,
+ in_be32((void *)GPIO0_OR) & ~CONFIG_SYS_TOUCH_RST);
udelay(1000);
- out32(GPIO0_OR, in32(GPIO0_OR) | CONFIG_SYS_TOUCH_RST);
+ out_be32((void *)GPIO0_OR,
+ in_be32((void *)GPIO0_OR) | CONFIG_SYS_TOUCH_RST);
/*
* Enable power on PS/2 interface (with reset)
*/
- *fpga_ctrl &= ~(CONFIG_SYS_FPGA_CTRL_PS2_PWR);
+ out_be16(FPGA_CTRL, in_be16(FPGA_CTRL) & ~FPGA_CTRL_PS2_PWR);
for (i=0;i<500;i++)
udelay(1000);
- *fpga_ctrl |= (CONFIG_SYS_FPGA_CTRL_PS2_PWR);
+ out_be16(FPGA_CTRL, in_be16(FPGA_CTRL) | FPGA_CTRL_PS2_PWR);
/*
* Get contrast value from environment variable
@@ -498,7 +519,8 @@ int misc_init_r (void)
if (str) {
contrast0 = simple_strtol(str, NULL, 16);
if (contrast0 > 255) {
- printf("ERROR: contrast0 value too high (0x%lx)!\n", contrast0);
+ printf("ERROR: contrast0 value too high (0x%lx)!\n",
+ contrast0);
contrast0 = 0xffffffff;
}
}
@@ -512,8 +534,9 @@ int misc_init_r (void)
/*
* Switch backlight on
*/
- *fpga_ctrl |= CONFIG_SYS_FPGA_CTRL_VGA0_BL;
- *lcd_backlight = 0x0000;
+ out_be16(FPGA_CTRL,
+ in_be16(FPGA_CTRL) | FPGA_CTRL_VGA0_BL);
+ out_be16(FPGA_BL, 0x0000);
lcd_setup(1, 0);
lcd_init((uchar *)CONFIG_SYS_LCD_BIG_REG, (uchar *)CONFIG_SYS_LCD_BIG_MEM,
@@ -524,8 +547,9 @@ int misc_init_r (void)
/*
* Switch backlight on
*/
- *fpga_ctrl &= ~CONFIG_SYS_FPGA_CTRL_VGA0_BL;
- *lcd_backlight = 0x0000;
+ out_be16(FPGA_CTRL,
+ in_be16(FPGA_CTRL) & ~FPGA_CTRL_VGA0_BL);
+ out_be16(FPGA_BL, 0x0000);
lcd_setup(1, 0);
lcd_init((uchar *)CONFIG_SYS_LCD_BIG_REG, (uchar *)CONFIG_SYS_LCD_BIG_MEM,
@@ -537,19 +561,22 @@ int misc_init_r (void)
* Set default display contrast voltage
*/
if (contrast0 == 0xffffffff) {
- *lcd_contrast = 0x0082;
+ out_be16(FPGA_CTR, 0x0082);
} else {
- *lcd_contrast = contrast0;
+ out_be16(FPGA_CTR, contrast0);
}
- *lcd_backlight = 0xffff;
+ out_be16(FPGA_BL, 0xffff);
/*
* Switch backlight on
*/
- *fpga_ctrl |= CONFIG_SYS_FPGA_CTRL_VGA0_BL | CONFIG_SYS_FPGA_CTRL_VGA0_BL_MODE;
+ out_be16(FPGA_CTRL,
+ in_be16(FPGA_CTRL) |
+ FPGA_CTRL_VGA0_BL |
+ FPGA_CTRL_VGA0_BL_MODE);
/*
* Set lcd clock (small epson)
*/
- *fpga_ctrl |= LCD_CLK_06250;
+ out_be16(FPGA_CTRL, in_be16(FPGA_CTRL) | LCD_CLK_06250);
udelay(100); /* wait for 100 us */
lcd_setup(0, 1);
@@ -562,19 +589,25 @@ int misc_init_r (void)
* Set default display contrast voltage
*/
if (contrast0 == 0xffffffff) {
- *lcd_contrast = 0x0060;
+ out_be16(FPGA_CTR, 0x0060);
} else {
- *lcd_contrast = contrast0;
+ out_be16(FPGA_CTR, contrast0);
}
- *lcd_backlight = 0xffff;
+ out_be16(FPGA_BL, 0xffff);
/*
* Switch backlight on
*/
- *fpga_ctrl |= CONFIG_SYS_FPGA_CTRL_VGA0_BL | CONFIG_SYS_FPGA_CTRL_VGA0_BL_MODE;
+ out_be16(FPGA_CTRL,
+ in_be16(FPGA_CTRL) |
+ FPGA_CTRL_VGA0_BL |
+ FPGA_CTRL_VGA0_BL_MODE);
/*
* Set lcd clock (small epson), enable 1-wire interface
*/
- *fpga_ctrl |= LCD_CLK_08330 | CONFIG_SYS_FPGA_CTRL_OW_ENABLE;
+ out_be16(FPGA_CTRL,
+ in_be16(FPGA_CTRL) |
+ LCD_CLK_08330 |
+ FPGA_CTRL_OW_ENABLE);
lcd_setup(0, 1);
lcd_init((uchar *)CONFIG_SYS_LCD_SMALL_REG, (uchar *)CONFIG_SYS_LCD_SMALL_MEM,
@@ -593,10 +626,10 @@ int misc_init_r (void)
puts("VGA: SM501 with 8 MB ");
if (strcmp(str, "ppc221") == 0) {
printf("(800*600, %dbpp)\n", BPP);
- *lcd_backlight = 0x002d; /* max. allowed brightness */
+ out_be16(FPGA_BL, 0x002d); /* max. allowed brightness */
} else if (strcmp(str, "ppc231") == 0) {
printf("(1024*768, %dbpp)\n", BPP);
- *lcd_backlight = 0x0000;
+ out_be16(FPGA_BL, 0x0000);
} else {
printf("Unsupported bd_type defined (%s) -> No display configured!\n", str);
return 0;
@@ -646,21 +679,21 @@ int checkboard (void)
#ifdef CONFIG_IDE_RESET
void ide_set_reset(int on)
{
- volatile unsigned short *fpga_mode =
- (unsigned short *)((ulong)CONFIG_SYS_FPGA_BASE_ADDR + CONFIG_SYS_FPGA_CTRL);
- volatile unsigned short *fpga_status =
- (unsigned short *)((ulong)CONFIG_SYS_FPGA_BASE_ADDR + CONFIG_SYS_FPGA_CTRL + 2);
-
- if (((gd->board_type >= 2) && (*fpga_status & CONFIG_SYS_FPGA_STATUS_CF_DETECT)) ||
+ if (((gd->board_type >= 2) &&
+ (in_be16(FPGA_STATUS) & FPGA_STATUS_CF_DETECT)) ||
(gd->board_type < 2)) {
/*
* Assert or deassert CompactFlash Reset Pin
*/
if (on) { /* assert RESET */
cf_enable();
- *fpga_mode &= ~(CONFIG_SYS_FPGA_CTRL_CF_RESET);
+ out_be16(FPGA_CTRL,
+ in_be16(FPGA_CTRL) &
+ ~FPGA_CTRL_CF_RESET);
} else { /* release RESET */
- *fpga_mode |= CONFIG_SYS_FPGA_CTRL_CF_RESET;
+ out_be16(FPGA_CTRL,
+ in_be16(FPGA_CTRL) |
+ FPGA_CTRL_CF_RESET);
}
}
}
@@ -684,17 +717,20 @@ int eeprom_write_enable (unsigned dev_addr, int state)
switch (state) {
case 1:
/* Enable write access, clear bit GPIO_SINT2. */
- out32(GPIO0_OR, in32(GPIO0_OR) & ~CONFIG_SYS_EEPROM_WP);
+ out_be32((void *)GPIO0_OR,
+ in_be32((void *)GPIO0_OR) & ~CONFIG_SYS_EEPROM_WP);
state = 0;
break;
case 0:
/* Disable write access, set bit GPIO_SINT2. */
- out32(GPIO0_OR, in32(GPIO0_OR) | CONFIG_SYS_EEPROM_WP);
+ out_be32((void *)GPIO0_OR,
+ in_be32((void *)GPIO0_OR) | CONFIG_SYS_EEPROM_WP);
state = 0;
break;
default:
/* Read current status back. */
- state = (0 == (in32(GPIO0_OR) & CONFIG_SYS_EEPROM_WP));
+ state = (0 == (in_be32((void *)GPIO0_OR) &
+ CONFIG_SYS_EEPROM_WP));
break;
}
}
diff --git a/board/esd/hh405/u-boot.lds b/board/esd/hh405/u-boot.lds
index 9697cc6..8c01016 100644
--- a/board/esd/hh405/u-boot.lds
+++ b/board/esd/hh405/u-boot.lds
@@ -57,22 +57,7 @@ SECTIONS
.plt : { *(.plt) }
.text :
{
- /* WARNING - the following is hand-optimized to fit within */
- /* the sector layout of our flash chips! XXX FIXME XXX */
-
cpu/ppc4xx/start.o (.text)
- cpu/ppc4xx/traps.o (.text)
- cpu/ppc4xx/interrupts.o (.text)
- cpu/ppc4xx/4xx_uart.o (.text)
- cpu/ppc4xx/cpu_init.o (.text)
- cpu/ppc4xx/speed.o (.text)
- common/dlmalloc.o (.text)
- lib_generic/crc32.o (.text)
- lib_ppc/extable.o (.text)
- lib_generic/zlib.o (.text)
-
-/* . = env_offset;*/
-/* common/env_embedded.o(.text)*/
*(.text)
*(.fixup)
@@ -82,10 +67,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/hub405/hub405.c b/board/esd/hub405/hub405.c
index 8785e6c..03e5ad7 100644
--- a/board/esd/hub405/hub405.c
+++ b/board/esd/hub405/hub405.c
@@ -23,6 +23,7 @@
#include <common.h>
#include <asm/processor.h>
+#include <asm/io.h>
#include <command.h>
#include <malloc.h>
@@ -44,22 +45,22 @@ int board_revision(void)
/*
* Setup GPIO pin(s) (IRQ6/GPIO23)
*/
- osrl_reg = in32(GPIO0_OSRH);
- isr1l_reg = in32(GPIO0_ISR1H);
- tcr_reg = in32(GPIO0_TCR);
- out32(GPIO0_OSRH, osrl_reg & ~0x00030000); /* output select */
- out32(GPIO0_ISR1H, isr1l_reg | 0x00030000); /* input select */
- out32(GPIO0_TCR, tcr_reg & ~0x00000100); /* select input */
+ osrl_reg = in_be32((void *)GPIO0_OSRH);
+ isr1l_reg = in_be32((void *)GPIO0_ISR1H);
+ tcr_reg = in_be32((void *)GPIO0_TCR);
+ out_be32((void *)GPIO0_OSRH, osrl_reg & ~0x00030000); /* output select */
+ out_be32((void *)GPIO0_ISR1H, isr1l_reg | 0x00030000); /* input select */
+ out_be32((void *)GPIO0_TCR, tcr_reg & ~0x00000100); /* select input */
udelay(1000); /* wait some time before reading input */
- value = in32(GPIO0_IR) & 0x00000100; /* get config bits */
+ value = in_be32((void *)GPIO0_IR) & 0x00000100; /* get config bits */
/*
* Restore GPIO settings
*/
- out32(GPIO0_OSRH, osrl_reg); /* output select */
- out32(GPIO0_ISR1H, isr1l_reg); /* input select */
- out32(GPIO0_TCR, tcr_reg); /* enable output driver for outputs */
+ out_be32((void *)GPIO0_OSRH, osrl_reg); /* output select */
+ out_be32((void *)GPIO0_ISR1H, isr1l_reg); /* input select */
+ out_be32((void *)GPIO0_TCR, tcr_reg); /* enable output driver for outputs */
if (value & 0x00000100) {
/* Revision 1.1 or 1.2 detected */
@@ -101,13 +102,9 @@ int board_early_init_f (void)
return 0;
}
+#define LED_REG (DUART0_BA + 0x20)
int misc_init_r (void)
{
- volatile unsigned char *duart0_mcr = (unsigned char *)((ulong)DUART0_BA + 4);
- volatile unsigned char *duart1_mcr = (unsigned char *)((ulong)DUART1_BA + 4);
- volatile unsigned char *duart2_mcr = (unsigned char *)((ulong)DUART2_BA + 4);
- volatile unsigned char *duart3_mcr = (unsigned char *)((ulong)DUART3_BA + 4);
- volatile unsigned char *led_reg = (unsigned char *)((ulong)DUART0_BA + 0x20);
unsigned long val;
int delay, flashcnt;
char *str;
@@ -116,16 +113,17 @@ int misc_init_r (void)
/*
* Enable interrupts in exar duart mcr[3]
*/
- *duart0_mcr = 0x08;
- *duart1_mcr = 0x08;
- *duart2_mcr = 0x08;
- *duart3_mcr = 0x08;
+ out_8((void *)(DUART0_BA + 4), 0x08);
+ out_8((void *)(DUART1_BA + 4), 0x08);
+ out_8((void *)(DUART2_BA + 4), 0x08);
+ out_8((void *)(DUART3_BA + 4), 0x08);
/*
* Set RS232/RS422 control (RS232 = high on GPIO)
*/
- val = in32(GPIO0_OR);
- val &= ~(CONFIG_SYS_UART2_RS232 | CONFIG_SYS_UART3_RS232 | CONFIG_SYS_UART4_RS232 | CONFIG_SYS_UART5_RS232);
+ val = in_be32((void *)GPIO0_OR);
+ val &= ~(CONFIG_SYS_UART2_RS232 | CONFIG_SYS_UART3_RS232 |
+ CONFIG_SYS_UART4_RS232 | CONFIG_SYS_UART5_RS232);
str = getenv("phys0");
if (!str || (str && (str[0] == '0')))
@@ -143,7 +141,7 @@ int misc_init_r (void)
if (!str || (str && (str[0] == '0')))
val |= CONFIG_SYS_UART5_RS232;
- out32(GPIO0_OR, val);
+ out_be32((void *)GPIO0_OR, val);
/*
* check board type and setup AP power
@@ -160,23 +158,27 @@ int misc_init_r (void)
* Flash LEDs
*/
for (flashcnt = 0; flashcnt < 3; flashcnt++) {
- *led_reg = led_reg_default; /* LED_A..D off */
+ /* LED_A..D off */
+ out_8((void *)LED_REG, led_reg_default);
for (delay = 0; delay < 100; delay++)
udelay(1000);
- *led_reg = led_reg_default | 0xf0; /* LED_A..D on */
+ /* LED_A..D on */
+ out_8((void *)LED_REG, led_reg_default | 0xf0);
for (delay = 0; delay < 50; delay++)
udelay(1000);
}
- *led_reg = led_reg_default;
+ out_8((void *)LED_REG, led_reg_default);
}
}
/*
* Reset external DUARTs
*/
- out32(GPIO0_OR, in32(GPIO0_OR) | CONFIG_SYS_DUART_RST); /* set reset to high */
+ out_be32((void *)GPIO0_OR,
+ in_be32((void *)GPIO0_OR) | CONFIG_SYS_DUART_RST); /* set reset to high */
udelay(10); /* wait 10us */
- out32(GPIO0_OR, in32(GPIO0_OR) & ~CONFIG_SYS_DUART_RST); /* set reset to low */
+ out_be32((void *)GPIO0_OR,
+ in_be32((void *)GPIO0_OR) & ~CONFIG_SYS_DUART_RST); /* set reset to low */
udelay(1000); /* wait 1ms */
/*
diff --git a/board/esd/hub405/u-boot.lds b/board/esd/hub405/u-boot.lds
index 6908106..005957e 100644
--- a/board/esd/hub405/u-boot.lds
+++ b/board/esd/hub405/u-boot.lds
@@ -57,23 +57,7 @@ SECTIONS
.plt : { *(.plt) }
.text :
{
- /* WARNING - the following is hand-optimized to fit within */
- /* the sector layout of our flash chips! XXX FIXME XXX */
-
cpu/ppc4xx/start.o (.text)
- cpu/ppc4xx/traps.o (.text)
- cpu/ppc4xx/interrupts.o (.text)
- cpu/ppc4xx/4xx_uart.o (.text)
- cpu/ppc4xx/cpu_init.o (.text)
- cpu/ppc4xx/speed.o (.text)
- drivers/net/4xx_enet.o (.text)
- common/dlmalloc.o (.text)
- lib_generic/crc32.o (.text)
- lib_ppc/extable.o (.text)
- lib_generic/zlib.o (.text)
-
-/* . = env_offset;*/
-/* common/env_embedded.o(.text)*/
*(.text)
*(.fixup)
@@ -83,10 +67,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/ocrtc/u-boot.lds b/board/esd/ocrtc/u-boot.lds
index 1fb754c..1b50b6d 100644
--- a/board/esd/ocrtc/u-boot.lds
+++ b/board/esd/ocrtc/u-boot.lds
@@ -82,10 +82,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/pci405/pci405.c b/board/esd/pci405/pci405.c
index 0602abf..8973f97 100644
--- a/board/esd/pci405/pci405.c
+++ b/board/esd/pci405/pci405.c
@@ -338,17 +338,17 @@ int checkboard (void)
}
/* ------------------------------------------------------------------------- */
+#define UART1_MCR 0xef600404
int wpeeprom(int wp)
{
int wp_state = wp;
- volatile unsigned char *uart1_mcr = (volatile unsigned char *)0xef600404;
if (wp == 1) {
- *uart1_mcr &= ~0x02;
+ out_8((void *)UART1_MCR, in_8((void *)UART1_MCR) & ~0x02);
} else if (wp == 0) {
- *uart1_mcr |= 0x02;
+ out_8((void *)UART1_MCR, in_8((void *)UART1_MCR) | 0x02);
} else {
- if (*uart1_mcr & 0x02) {
+ if (in_8((void *)UART1_MCR) & 0x02) {
wp_state = 0;
} else {
wp_state = 1;
diff --git a/board/esd/pci405/u-boot.lds b/board/esd/pci405/u-boot.lds
index 9697cc6..8c01016 100644
--- a/board/esd/pci405/u-boot.lds
+++ b/board/esd/pci405/u-boot.lds
@@ -57,22 +57,7 @@ SECTIONS
.plt : { *(.plt) }
.text :
{
- /* WARNING - the following is hand-optimized to fit within */
- /* the sector layout of our flash chips! XXX FIXME XXX */
-
cpu/ppc4xx/start.o (.text)
- cpu/ppc4xx/traps.o (.text)
- cpu/ppc4xx/interrupts.o (.text)
- cpu/ppc4xx/4xx_uart.o (.text)
- cpu/ppc4xx/cpu_init.o (.text)
- cpu/ppc4xx/speed.o (.text)
- common/dlmalloc.o (.text)
- lib_generic/crc32.o (.text)
- lib_ppc/extable.o (.text)
- lib_generic/zlib.o (.text)
-
-/* . = env_offset;*/
-/* common/env_embedded.o(.text)*/
*(.text)
*(.fixup)
@@ -82,10 +67,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/plu405/plu405.c b/board/esd/plu405/plu405.c
index 7c0aaa2..a94604a 100644
--- a/board/esd/plu405/plu405.c
+++ b/board/esd/plu405/plu405.c
@@ -237,18 +237,18 @@ int checkboard (void)
}
#ifdef CONFIG_IDE_RESET
+#define FPGA_CTRL (CONFIG_SYS_FPGA_BASE_ADDR + CONFIG_SYS_FPGA_CTRL)
void ide_set_reset(int on)
{
- volatile unsigned short *fpga_mode =
- (unsigned short *)((ulong)CONFIG_SYS_FPGA_BASE_ADDR + CONFIG_SYS_FPGA_CTRL);
-
/*
* Assert or deassert CompactFlash Reset Pin
*/
if (on) { /* assert RESET */
- *fpga_mode &= ~(CONFIG_SYS_FPGA_CTRL_CF_RESET);
+ out_be16((void *)FPGA_CTRL,
+ in_be16((void *)FPGA_CTRL) & ~CONFIG_SYS_FPGA_CTRL_CF_RESET);
} else { /* release RESET */
- *fpga_mode |= CONFIG_SYS_FPGA_CTRL_CF_RESET;
+ out_be16((void *)FPGA_CTRL,
+ in_be16((void *)FPGA_CTRL) | CONFIG_SYS_FPGA_CTRL_CF_RESET);
}
}
#endif /* CONFIG_IDE_RESET */
diff --git a/board/esd/plu405/u-boot.lds b/board/esd/plu405/u-boot.lds
index fd5f3df..005957e 100644
--- a/board/esd/plu405/u-boot.lds
+++ b/board/esd/plu405/u-boot.lds
@@ -57,9 +57,6 @@ SECTIONS
.plt : { *(.plt) }
.text :
{
- /* WARNING - the following is hand-optimized to fit within */
- /* the sector layout of our flash chips! XXX FIXME XXX */
-
cpu/ppc4xx/start.o (.text)
*(.text)
@@ -70,10 +67,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/pmc405/u-boot.lds b/board/esd/pmc405/u-boot.lds
index ca615f5..74f1d87 100644
--- a/board/esd/pmc405/u-boot.lds
+++ b/board/esd/pmc405/u-boot.lds
@@ -57,22 +57,7 @@ SECTIONS
.plt : { *(.plt) }
.text :
{
- /* WARNING - the following is hand-optimized to fit within */
- /* the sector layout of our flash chips! XXX FIXME XXX */
-
cpu/ppc4xx/start.o (.text)
- cpu/ppc4xx/traps.o (.text)
- cpu/ppc4xx/interrupts.o (.text)
- cpu/ppc4xx/4xx_uart.o (.text)
- cpu/ppc4xx/cpu_init.o (.text)
- cpu/ppc4xx/speed.o (.text)
- common/dlmalloc.o (.text)
- lib_generic/crc32.o (.text)
- lib_ppc/extable.o (.text)
- lib_generic/zlib.o (.text)
-
-/* . = env_offset;*/
-/* common/env_embedded.o(.text)*/
*(.text)
*(.fixup)
@@ -82,10 +67,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/pmc440/cmd_pmc440.c b/board/esd/pmc440/cmd_pmc440.c
index 7808d4d..0fbc3dc 100644
--- a/board/esd/pmc440/cmd_pmc440.c
+++ b/board/esd/pmc440/cmd_pmc440.c
@@ -242,7 +242,7 @@ int do_fifo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
"address %08x\n",
n, data, f);
for (i=0; i<n; i++)
- out32(f, data);
+ out_be32((void *)f, data);
}
} else {
printf("Usage:\nfifo %s\n", cmdtp->help);
diff --git a/board/esd/pmc440/pmc440.c b/board/esd/pmc440/pmc440.c
index 3824105..2ab944d 100644
--- a/board/esd/pmc440/pmc440.c
+++ b/board/esd/pmc440/pmc440.c
@@ -107,31 +107,31 @@ int board_early_init_f(void)
* Setup the GPIO pins
* TODO: setup GPIOs via CONFIG_SYS_4xx_GPIO_TABLE in board's config file
*/
- out32(GPIO0_OR, 0x40000102);
- out32(GPIO0_TCR, 0x4c90011f);
- out32(GPIO0_OSRL, 0x28051400);
- out32(GPIO0_OSRH, 0x55005000);
- out32(GPIO0_TSRL, 0x08051400);
- out32(GPIO0_TSRH, 0x55005000);
- out32(GPIO0_ISR1L, 0x54000000);
- out32(GPIO0_ISR1H, 0x00000000);
- out32(GPIO0_ISR2L, 0x44000000);
- out32(GPIO0_ISR2H, 0x00000100);
- out32(GPIO0_ISR3L, 0x00000000);
- out32(GPIO0_ISR3H, 0x00000000);
-
- out32(GPIO1_OR, 0x80002408);
- out32(GPIO1_TCR, 0xd6003c08);
- out32(GPIO1_OSRL, 0x0a5a0000);
- out32(GPIO1_OSRH, 0x00000000);
- out32(GPIO1_TSRL, 0x00000000);
- out32(GPIO1_TSRH, 0x00000000);
- out32(GPIO1_ISR1L, 0x00005555);
- out32(GPIO1_ISR1H, 0x40000000);
- out32(GPIO1_ISR2L, 0x04010000);
- out32(GPIO1_ISR2H, 0x00000000);
- out32(GPIO1_ISR3L, 0x01400000);
- out32(GPIO1_ISR3H, 0x00000000);
+ out_be32((void *)GPIO0_OR, 0x40000102);
+ out_be32((void *)GPIO0_TCR, 0x4c90011f);
+ out_be32((void *)GPIO0_OSRL, 0x28051400);
+ out_be32((void *)GPIO0_OSRH, 0x55005000);
+ out_be32((void *)GPIO0_TSRL, 0x08051400);
+ out_be32((void *)GPIO0_TSRH, 0x55005000);
+ out_be32((void *)GPIO0_ISR1L, 0x54000000);
+ out_be32((void *)GPIO0_ISR1H, 0x00000000);
+ out_be32((void *)GPIO0_ISR2L, 0x44000000);
+ out_be32((void *)GPIO0_ISR2H, 0x00000100);
+ out_be32((void *)GPIO0_ISR3L, 0x00000000);
+ out_be32((void *)GPIO0_ISR3H, 0x00000000);
+
+ out_be32((void *)GPIO1_OR, 0x80002408);
+ out_be32((void *)GPIO1_TCR, 0xd6003c08);
+ out_be32((void *)GPIO1_OSRL, 0x0a5a0000);
+ out_be32((void *)GPIO1_OSRH, 0x00000000);
+ out_be32((void *)GPIO1_TSRL, 0x00000000);
+ out_be32((void *)GPIO1_TSRH, 0x00000000);
+ out_be32((void *)GPIO1_ISR1L, 0x00005555);
+ out_be32((void *)GPIO1_ISR1H, 0x40000000);
+ out_be32((void *)GPIO1_ISR2L, 0x04010000);
+ out_be32((void *)GPIO1_ISR2H, 0x00000000);
+ out_be32((void *)GPIO1_ISR3L, 0x01400000);
+ out_be32((void *)GPIO1_ISR3H, 0x00000000);
/* patch PLB:PCI divider for 66MHz PCI */
mfcpr(clk_spcid, reg);
@@ -804,17 +804,20 @@ int eeprom_write_enable(unsigned dev_addr, int state)
switch (state) {
case 1:
/* Enable write access, clear bit GPIO_SINT2. */
- out32(GPIO0_OR, in32(GPIO0_OR) & ~GPIO0_EP_EEP);
+ out_be32((void *)GPIO0_OR,
+ in_be32((void *)GPIO0_OR) & ~GPIO0_EP_EEP);
state = 0;
break;
case 0:
/* Disable write access, set bit GPIO_SINT2. */
- out32(GPIO0_OR, in32(GPIO0_OR) | GPIO0_EP_EEP);
+ out_be32((void *)GPIO0_OR,
+ in_be32((void *)GPIO0_OR) | GPIO0_EP_EEP);
state = 0;
break;
default:
/* Read current status back. */
- state = (0 == (in32(GPIO0_OR) & GPIO0_EP_EEP));
+ state = (0 == (in_be32((void *)GPIO0_OR)
+ & GPIO0_EP_EEP));
break;
}
}
diff --git a/board/esd/pmc440/u-boot-nand.lds b/board/esd/pmc440/u-boot-nand.lds
index 6e1e169..b580e0b 100644
--- a/board/esd/pmc440/u-boot-nand.lds
+++ b/board/esd/pmc440/u-boot-nand.lds
@@ -69,9 +69,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/pmc440/u-boot.lds b/board/esd/pmc440/u-boot.lds
index 05152b7..7360349 100644
--- a/board/esd/pmc440/u-boot.lds
+++ b/board/esd/pmc440/u-boot.lds
@@ -62,9 +62,6 @@ SECTIONS
.plt : { *(.plt) }
.text :
{
- /* WARNING - the following is hand-optimized to fit within */
- /* the sector layout of our flash chips! XXX FIXME XXX */
-
cpu/ppc4xx/start.o (.text)
*(.text)
@@ -75,9 +72,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/tasreg/tasreg.c b/board/esd/tasreg/tasreg.c
index 80ff237..760c71d 100644
--- a/board/esd/tasreg/tasreg.c
+++ b/board/esd/tasreg/tasreg.c
@@ -25,6 +25,7 @@
#include <command.h>
#include <malloc.h>
#include <asm/m5249.h>
+#include <asm/io.h>
/* Prototypes */
@@ -118,7 +119,7 @@ phys_size_t initdram (int board_type) {
/** Precharge sequence **/
mbar_writeLong(MCFSIM_DACR0, 0x0000332c); /* Set DACR0[IP] (bit 3) */
- *((volatile unsigned long *) 0x00) = junk; /* write to a memory location to init. precharge */
+ out_be32((void *)0, junk); /* write to a memory location to init. precharge */
udelay(0x10); /* Allow several Precharge cycles */
/** Refresh Sequence **/
@@ -127,7 +128,7 @@ phys_size_t initdram (int board_type) {
/** Mode Register initialization **/
mbar_writeLong(MCFSIM_DACR0, 0x0000b364); /* Enable DACR0[IMRS] (bit 6); RE remains enabled */
- *((volatile unsigned long *) 0x800) = junk; /* Access RAM to initialize the mode register */
+ out_be32((void *)0x800, junk); /* Access RAM to initialize the mode register */
return CONFIG_SYS_SDRAM_SIZE * 1024 * 1024;
};
@@ -258,7 +259,7 @@ int do_codec(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
uchar buf[8];
- *(volatile ushort *)0xe0000000 = 0x4000;
+ out_be16((void *)0xe0000000, 0x4000);
udelay(5000); /* wait for 5ms */
diff --git a/board/esd/tasreg/u-boot.lds b/board/esd/tasreg/u-boot.lds
index aec7e9b..e3230b9 100644
--- a/board/esd/tasreg/u-boot.lds
+++ b/board/esd/tasreg/u-boot.lds
@@ -72,10 +72,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/voh405/u-boot.lds b/board/esd/voh405/u-boot.lds
index d8fbea3..8c01016 100644
--- a/board/esd/voh405/u-boot.lds
+++ b/board/esd/voh405/u-boot.lds
@@ -57,23 +57,7 @@ SECTIONS
.plt : { *(.plt) }
.text :
{
- /* WARNING - the following is hand-optimized to fit within */
- /* the sector layout of our flash chips! XXX FIXME XXX */
-
cpu/ppc4xx/start.o (.text)
- cpu/ppc4xx/traps.o (.text)
- cpu/ppc4xx/interrupts.o (.text)
- cpu/ppc4xx/4xx_uart.o (.text)
- cpu/ppc4xx/cpu_init.o (.text)
- cpu/ppc4xx/speed.o (.text)
- drivers/net/4xx_enet.o (.text)
- common/dlmalloc.o (.text)
- lib_generic/crc32.o (.text)
- lib_ppc/extable.o (.text)
- lib_generic/zlib.o (.text)
-
-/* . = env_offset;*/
-/* common/env_embedded.o(.text)*/
*(.text)
*(.fixup)
@@ -83,10 +67,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/voh405/voh405.c b/board/esd/voh405/voh405.c
index 5480105..96a04b3 100644
--- a/board/esd/voh405/voh405.c
+++ b/board/esd/voh405/voh405.c
@@ -297,18 +297,18 @@ int checkboard (void)
}
#ifdef CONFIG_IDE_RESET
+#define FPGA_MODE (CONFIG_SYS_FPGA_BASE_ADDR + CONFIG_SYS_FPGA_CTRL)
void ide_set_reset(int on)
{
- volatile unsigned short *fpga_mode =
- (unsigned short *)((ulong)CONFIG_SYS_FPGA_BASE_ADDR + CONFIG_SYS_FPGA_CTRL);
-
/*
* Assert or deassert CompactFlash Reset Pin
*/
if (on) { /* assert RESET */
- *fpga_mode &= ~(CONFIG_SYS_FPGA_CTRL_CF_RESET);
+ out_be16((void *)FPGA_MODE,
+ in_be16((void *)FPGA_MODE) & ~CONFIG_SYS_FPGA_CTRL_CF_RESET);
} else { /* release RESET */
- *fpga_mode |= CONFIG_SYS_FPGA_CTRL_CF_RESET;
+ out_be16((void *)FPGA_MODE,
+ in_be16((void *)FPGA_MODE) | CONFIG_SYS_FPGA_CTRL_CF_RESET);
}
}
#endif /* CONFIG_IDE_RESET */
diff --git a/board/esd/vom405/u-boot.lds b/board/esd/vom405/u-boot.lds
index c9472f9..8c01016 100644
--- a/board/esd/vom405/u-boot.lds
+++ b/board/esd/vom405/u-boot.lds
@@ -57,9 +57,6 @@ SECTIONS
.plt : { *(.plt) }
.text :
{
- /* WARNING - the following is hand-optimized to fit within */
- /* the sector layout of our flash chips! XXX FIXME XXX */
-
cpu/ppc4xx/start.o (.text)
*(.text)
@@ -70,10 +67,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/vom405/vom405.c b/board/esd/vom405/vom405.c
index 1b1479f..d67b23e 100644
--- a/board/esd/vom405/vom405.c
+++ b/board/esd/vom405/vom405.c
@@ -23,6 +23,7 @@
#include <common.h>
#include <asm/processor.h>
+#include <asm/io.h>
#include <command.h>
#include <malloc.h>
@@ -67,9 +68,11 @@ int board_early_init_f (void)
/*
* Reset CPLD via GPIO12 (CS3) pin
*/
- out32(GPIO0_OR, in32(GPIO0_OR) & ~(0x80000000 >> 12));
+ out_be32((void *)GPIO0_OR,
+ in_be32((void *)GPIO0_OR) & ~(0x80000000 >> 12));
udelay(1000); /* wait 1ms */
- out32(GPIO0_OR, in32(GPIO0_OR) | (0x80000000 >> 12));
+ out_be32((void *)GPIO0_OR,
+ in_be32((void *)GPIO0_OR) | (0x80000000 >> 12));
udelay(1000); /* wait 1ms */
return 0;
@@ -93,7 +96,7 @@ int checkboard (void)
int i = getenv_r ("serial#", str, sizeof(str));
int flashcnt;
int delay;
- volatile unsigned char *led_reg = (unsigned char *)((ulong)CAN_BA + 0x1000);
+ u8 *led_reg = (u8 *)(CAN_BA + 0x1000);
puts ("Board: ");
@@ -103,20 +106,20 @@ int checkboard (void)
puts(str);
}
- printf(" (PLD-Version=%02d)\n", *led_reg);
+ printf(" (PLD-Version=%02d)\n", in_8(led_reg));
/*
* Flash LEDs
*/
for (flashcnt = 0; flashcnt < 3; flashcnt++) {
- *led_reg = 0x40; /* LED_B..D off */
+ out_8(led_reg, 0x40); /* LED_B..D off */
for (delay = 0; delay < 100; delay++)
udelay(1000);
- *led_reg = 0x47; /* LED_B..D on */
+ out_8(led_reg, 0x47); /* LED_B..D on */
for (delay = 0; delay < 50; delay++)
udelay(1000);
}
- *led_reg = 0x40;
+ out_8(led_reg, 0x40);
return 0;
}
diff --git a/board/esd/wuh405/u-boot.lds b/board/esd/wuh405/u-boot.lds
index e2e2512..005957e 100644
--- a/board/esd/wuh405/u-boot.lds
+++ b/board/esd/wuh405/u-boot.lds
@@ -57,22 +57,7 @@ SECTIONS
.plt : { *(.plt) }
.text :
{
- /* WARNING - the following is hand-optimized to fit within */
- /* the sector layout of our flash chips! XXX FIXME XXX */
-
cpu/ppc4xx/start.o (.text)
- cpu/ppc4xx/traps.o (.text)
- cpu/ppc4xx/interrupts.o (.text)
- cpu/ppc4xx/4xx_uart.o (.text)
- cpu/ppc4xx/cpu_init.o (.text)
- cpu/ppc4xx/speed.o (.text)
- common/dlmalloc.o (.text)
- lib_generic/crc32.o (.text)
- lib_ppc/extable.o (.text)
- lib_generic/zlib.o (.text)
-
-/* . = env_offset;*/
-/* common/env_embedded.o(.text)*/
*(.text)
*(.fixup)
@@ -82,10 +67,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/esd/wuh405/wuh405.c b/board/esd/wuh405/wuh405.c
index 5eca3bd..e330fff 100644
--- a/board/esd/wuh405/wuh405.c
+++ b/board/esd/wuh405/wuh405.c
@@ -82,10 +82,6 @@ int board_early_init_f (void)
int misc_init_r (void)
{
- volatile unsigned char *duart0_mcr = (unsigned char *)((ulong)DUART0_BA + 4);
- volatile unsigned char *duart1_mcr = (unsigned char *)((ulong)DUART1_BA + 4);
- volatile unsigned char *duart2_mcr = (unsigned char *)((ulong)DUART2_BA + 4);
- volatile unsigned char *duart3_mcr = (unsigned char *)((ulong)DUART3_BA + 4);
unsigned char *dst;
ulong len = sizeof(fpgadata);
int status;
@@ -155,18 +151,20 @@ int misc_init_r (void)
/*
* Reset external DUARTs
*/
- out32(GPIO0_OR, in32(GPIO0_OR) | CONFIG_SYS_DUART_RST); /* set reset to high */
+ out_be32((void *)GPIO0_OR,
+ in_be32((void *)GPIO0_OR) | CONFIG_SYS_DUART_RST);
udelay(10); /* wait 10us */
- out32(GPIO0_OR, in32(GPIO0_OR) & ~CONFIG_SYS_DUART_RST); /* set reset to low */
+ out_be32((void *)GPIO0_OR,
+ in_be32((void *)GPIO0_OR) & ~CONFIG_SYS_DUART_RST);
udelay(1000); /* wait 1ms */
/*
* Enable interrupts in exar duart mcr[3]
*/
- *duart0_mcr = 0x08;
- *duart1_mcr = 0x08;
- *duart2_mcr = 0x08;
- *duart3_mcr = 0x08;
+ out_8((void *)(DUART0_BA + 4), 0x08);
+ out_8((void *)(DUART1_BA + 4), 0x08);
+ out_8((void *)(DUART2_BA + 4), 0x08);
+ out_8((void *)(DUART3_BA + 4), 0x08);
return (0);
}
diff --git a/board/esteem192e/u-boot.lds b/board/esteem192e/u-boot.lds
index c4e17d6..57aabed 100644
--- a/board/esteem192e/u-boot.lds
+++ b/board/esteem192e/u-boot.lds
@@ -73,10 +73,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/etin/debris/debris.c b/board/etin/debris/debris.c
index 227c49a..a971af3 100644
--- a/board/etin/debris/debris.c
+++ b/board/etin/debris/debris.c
@@ -173,9 +173,13 @@ void nvram_write(long dest, const void *src, size_t count)
int misc_init_r(void)
{
- /* Write ethernet addr in NVRAM for VxWorks */
- nvram_write(CONFIG_ENV_ADDR + CONFIG_SYS_NVRAM_VXWORKS_OFFS,
- (char*)&gd->bd->bi_enetaddr[0], 6);
+ uchar ethaddr[6];
+
+ if (eth_getenv_enetaddr("ethaddr", ethaddr))
+ /* Write ethernet addr in NVRAM for VxWorks */
+ nvram_write(CONFIG_ENV_ADDR + CONFIG_SYS_NVRAM_VXWORKS_OFFS,
+ ethaddr, 6);
+
return 0;
}
diff --git a/board/etx094/u-boot.lds b/board/etx094/u-boot.lds
index 340825e..eb3d487 100644
--- a/board/etx094/u-boot.lds
+++ b/board/etx094/u-boot.lds
@@ -75,10 +75,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/evb4510/u-boot.lds b/board/evb4510/u-boot.lds
index a435466..b72e126 100644
--- a/board/evb4510/u-boot.lds
+++ b/board/evb4510/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/evb64260/u-boot.lds b/board/evb64260/u-boot.lds
index ff2d8b7..632921a 100644
--- a/board/evb64260/u-boot.lds
+++ b/board/evb64260/u-boot.lds
@@ -70,10 +70,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/exbitgen/u-boot.lds b/board/exbitgen/u-boot.lds
index d76b97e..2798dc8 100644
--- a/board/exbitgen/u-boot.lds
+++ b/board/exbitgen/u-boot.lds
@@ -84,10 +84,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/fads/fads.h b/board/fads/fads.h
index 24e43ea..4ab4b26 100644
--- a/board/fads/fads.h
+++ b/board/fads/fads.h
@@ -241,7 +241,7 @@
*
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
@@ -249,7 +249,7 @@
/* mtdparts command line support */
/* Note: fake mtd_id used, no linux mtd map file */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=fads0,nor1=fads-1,nor2=fads-2,nor3=fads-3"
#define MTDPARTS_DEFAULT "mtdparts=fads-0:-@1m(user1),fads-1:-(user2),fads-2:-(user3),fads-3:-(user4)"
*/
diff --git a/board/fads/u-boot.lds b/board/fads/u-boot.lds
index 194ca69..b39ef14 100644
--- a/board/fads/u-boot.lds
+++ b/board/fads/u-boot.lds
@@ -63,10 +63,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/flagadm/u-boot.lds b/board/flagadm/u-boot.lds
index f36259a..1c8180a 100644
--- a/board/flagadm/u-boot.lds
+++ b/board/flagadm/u-boot.lds
@@ -62,10 +62,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/freescale/m5249evb/u-boot.lds b/board/freescale/m5249evb/u-boot.lds
index aec7e9b..e3230b9 100644
--- a/board/freescale/m5249evb/u-boot.lds
+++ b/board/freescale/m5249evb/u-boot.lds
@@ -72,10 +72,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/freescale/m5253demo/u-boot.lds b/board/freescale/m5253demo/u-boot.lds
index a295764..6cb5ee0 100644
--- a/board/freescale/m5253demo/u-boot.lds
+++ b/board/freescale/m5253demo/u-boot.lds
@@ -73,8 +73,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/freescale/m5253evbe/u-boot.lds b/board/freescale/m5253evbe/u-boot.lds
index 239cf95..132fccf 100644
--- a/board/freescale/m5253evbe/u-boot.lds
+++ b/board/freescale/m5253evbe/u-boot.lds
@@ -72,8 +72,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/freescale/m5271evb/u-boot.lds b/board/freescale/m5271evb/u-boot.lds
index 0bc7fa1..00c1f2a 100644
--- a/board/freescale/m5271evb/u-boot.lds
+++ b/board/freescale/m5271evb/u-boot.lds
@@ -73,8 +73,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/freescale/m5272c3/u-boot.lds b/board/freescale/m5272c3/u-boot.lds
index e5c7b67..9d20b22 100644
--- a/board/freescale/m5272c3/u-boot.lds
+++ b/board/freescale/m5272c3/u-boot.lds
@@ -72,8 +72,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/freescale/m5275evb/u-boot.lds b/board/freescale/m5275evb/u-boot.lds
index a3e03d5..daf8724 100644
--- a/board/freescale/m5275evb/u-boot.lds
+++ b/board/freescale/m5275evb/u-boot.lds
@@ -71,8 +71,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/freescale/m5282evb/u-boot.lds b/board/freescale/m5282evb/u-boot.lds
index 707b228..dc18b7d 100644
--- a/board/freescale/m5282evb/u-boot.lds
+++ b/board/freescale/m5282evb/u-boot.lds
@@ -72,8 +72,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/freescale/m53017evb/u-boot.lds b/board/freescale/m53017evb/u-boot.lds
index dc53141..c79d06c 100644
--- a/board/freescale/m53017evb/u-boot.lds
+++ b/board/freescale/m53017evb/u-boot.lds
@@ -72,8 +72,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/freescale/m5329evb/u-boot.lds b/board/freescale/m5329evb/u-boot.lds
index c9da922..af31098 100644
--- a/board/freescale/m5329evb/u-boot.lds
+++ b/board/freescale/m5329evb/u-boot.lds
@@ -72,8 +72,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/freescale/m5373evb/u-boot.lds b/board/freescale/m5373evb/u-boot.lds
index fcf1ff1..dff74b6 100644
--- a/board/freescale/m5373evb/u-boot.lds
+++ b/board/freescale/m5373evb/u-boot.lds
@@ -72,8 +72,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/freescale/m547xevb/u-boot.lds b/board/freescale/m547xevb/u-boot.lds
index c25c8dc..a3014bd 100644
--- a/board/freescale/m547xevb/u-boot.lds
+++ b/board/freescale/m547xevb/u-boot.lds
@@ -71,8 +71,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/freescale/m548xevb/u-boot.lds b/board/freescale/m548xevb/u-boot.lds
index c25c8dc..a3014bd 100644
--- a/board/freescale/m548xevb/u-boot.lds
+++ b/board/freescale/m548xevb/u-boot.lds
@@ -71,8 +71,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/freescale/mpc7448hpc2/u-boot.lds b/board/freescale/mpc7448hpc2/u-boot.lds
index f3f6c54..cd11f39 100644
--- a/board/freescale/mpc7448hpc2/u-boot.lds
+++ b/board/freescale/mpc7448hpc2/u-boot.lds
@@ -70,9 +70,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/freescale/mpc8536ds/u-boot.lds b/board/freescale/mpc8536ds/u-boot.lds
index 901f633..f4ff756 100644
--- a/board/freescale/mpc8536ds/u-boot.lds
+++ b/board/freescale/mpc8536ds/u-boot.lds
@@ -65,10 +65,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
} :text
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/freescale/mpc8540ads/u-boot.lds b/board/freescale/mpc8540ads/u-boot.lds
index 515d320..41ff3f3 100644
--- a/board/freescale/mpc8540ads/u-boot.lds
+++ b/board/freescale/mpc8540ads/u-boot.lds
@@ -68,10 +68,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
} :text
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/freescale/mpc8541cds/u-boot.lds b/board/freescale/mpc8541cds/u-boot.lds
index d728d8b..35d5ff2 100644
--- a/board/freescale/mpc8541cds/u-boot.lds
+++ b/board/freescale/mpc8541cds/u-boot.lds
@@ -65,10 +65,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
} :text
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/freescale/mpc8544ds/u-boot.lds b/board/freescale/mpc8544ds/u-boot.lds
index a05ece5..159642d 100644
--- a/board/freescale/mpc8544ds/u-boot.lds
+++ b/board/freescale/mpc8544ds/u-boot.lds
@@ -65,10 +65,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
} :text
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/freescale/mpc8548cds/u-boot.lds b/board/freescale/mpc8548cds/u-boot.lds
index d4a2f72..c363fe7 100644
--- a/board/freescale/mpc8548cds/u-boot.lds
+++ b/board/freescale/mpc8548cds/u-boot.lds
@@ -65,10 +65,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
} :text
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/freescale/mpc8555cds/u-boot.lds b/board/freescale/mpc8555cds/u-boot.lds
index 11885e8..d6584a5 100644
--- a/board/freescale/mpc8555cds/u-boot.lds
+++ b/board/freescale/mpc8555cds/u-boot.lds
@@ -65,10 +65,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
} :text
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/freescale/mpc8560ads/u-boot.lds b/board/freescale/mpc8560ads/u-boot.lds
index 515d320..41ff3f3 100644
--- a/board/freescale/mpc8560ads/u-boot.lds
+++ b/board/freescale/mpc8560ads/u-boot.lds
@@ -68,10 +68,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
} :text
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/freescale/mpc8568mds/u-boot.lds b/board/freescale/mpc8568mds/u-boot.lds
index ad96410..ffc1888 100644
--- a/board/freescale/mpc8568mds/u-boot.lds
+++ b/board/freescale/mpc8568mds/u-boot.lds
@@ -65,10 +65,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
} :text
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/freescale/mpc8572ds/u-boot.lds b/board/freescale/mpc8572ds/u-boot.lds
index a05ece5..159642d 100644
--- a/board/freescale/mpc8572ds/u-boot.lds
+++ b/board/freescale/mpc8572ds/u-boot.lds
@@ -65,10 +65,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
} :text
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/freescale/mpc8610hpcd/u-boot.lds b/board/freescale/mpc8610hpcd/u-boot.lds
index 4127492..5cc88ae 100644
--- a/board/freescale/mpc8610hpcd/u-boot.lds
+++ b/board/freescale/mpc8610hpcd/u-boot.lds
@@ -68,10 +68,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/freescale/mpc8641hpcn/u-boot.lds b/board/freescale/mpc8641hpcn/u-boot.lds
index 6c9da1f..e188722 100644
--- a/board/freescale/mpc8641hpcn/u-boot.lds
+++ b/board/freescale/mpc8641hpcn/u-boot.lds
@@ -69,10 +69,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/freescale/mx31ads/u-boot.lds b/board/freescale/mx31ads/u-boot.lds
index e682f30..079184e 100644
--- a/board/freescale/mx31ads/u-boot.lds
+++ b/board/freescale/mx31ads/u-boot.lds
@@ -50,7 +50,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/g2000/u-boot.lds b/board/g2000/u-boot.lds
index d8fbea3..8c01016 100644
--- a/board/g2000/u-boot.lds
+++ b/board/g2000/u-boot.lds
@@ -57,23 +57,7 @@ SECTIONS
.plt : { *(.plt) }
.text :
{
- /* WARNING - the following is hand-optimized to fit within */
- /* the sector layout of our flash chips! XXX FIXME XXX */
-
cpu/ppc4xx/start.o (.text)
- cpu/ppc4xx/traps.o (.text)
- cpu/ppc4xx/interrupts.o (.text)
- cpu/ppc4xx/4xx_uart.o (.text)
- cpu/ppc4xx/cpu_init.o (.text)
- cpu/ppc4xx/speed.o (.text)
- drivers/net/4xx_enet.o (.text)
- common/dlmalloc.o (.text)
- lib_generic/crc32.o (.text)
- lib_ppc/extable.o (.text)
- lib_generic/zlib.o (.text)
-
-/* . = env_offset;*/
-/* common/env_embedded.o(.text)*/
*(.text)
*(.fixup)
@@ -83,10 +67,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/gaisler/gr_cpci_ax2000/u-boot.lds b/board/gaisler/gr_cpci_ax2000/u-boot.lds
index a087631..d5d7842 100644
--- a/board/gaisler/gr_cpci_ax2000/u-boot.lds
+++ b/board/gaisler/gr_cpci_ax2000/u-boot.lds
@@ -77,10 +77,8 @@ SECTIONS
*(.gnu.warning)
/* *(.got1)*/
. = ALIGN(16);
- *(.rodata)
- *(.rodata1)
- *(.rodata.*)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
. = ALIGN(4);
_etext = .;
diff --git a/board/gaisler/gr_ep2s60/u-boot.lds b/board/gaisler/gr_ep2s60/u-boot.lds
index e461a36..99aa0ad 100644
--- a/board/gaisler/gr_ep2s60/u-boot.lds
+++ b/board/gaisler/gr_ep2s60/u-boot.lds
@@ -77,10 +77,8 @@ SECTIONS
*(.gnu.warning)
/* *(.got1)*/
. = ALIGN(16);
- *(.rodata)
- *(.rodata1)
- *(.rodata.*)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
. = ALIGN(4);
_etext = .;
diff --git a/board/gaisler/gr_xc3s_1500/u-boot.lds b/board/gaisler/gr_xc3s_1500/u-boot.lds
index ddd27d4..3b13190 100644
--- a/board/gaisler/gr_xc3s_1500/u-boot.lds
+++ b/board/gaisler/gr_xc3s_1500/u-boot.lds
@@ -77,10 +77,8 @@ SECTIONS
*(.gnu.warning)
/* *(.got1)*/
. = ALIGN(16);
- *(.rodata)
- *(.rodata1)
- *(.rodata.*)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
. = ALIGN(4);
_etext = .;
diff --git a/board/gaisler/grsim/u-boot.lds b/board/gaisler/grsim/u-boot.lds
index a9cc7ca..0fa6627 100644
--- a/board/gaisler/grsim/u-boot.lds
+++ b/board/gaisler/grsim/u-boot.lds
@@ -76,10 +76,8 @@ SECTIONS
*(.gnu.warning)
/* *(.got1)*/
. = ALIGN(16);
- *(.rodata)
- *(.rodata1)
- *(.rodata.*)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
. = ALIGN(4);
_etext = .;
diff --git a/board/gaisler/grsim_leon2/u-boot.lds b/board/gaisler/grsim_leon2/u-boot.lds
index b3462d4..c5311a6 100644
--- a/board/gaisler/grsim_leon2/u-boot.lds
+++ b/board/gaisler/grsim_leon2/u-boot.lds
@@ -76,10 +76,8 @@ SECTIONS
*(.gnu.warning)
/* *(.got1)*/
. = ALIGN(16);
- *(.rodata)
- *(.rodata1)
- *(.rodata.*)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
. = ALIGN(4);
_etext = .;
diff --git a/board/gcplus/u-boot.lds b/board/gcplus/u-boot.lds
index ab7f76b..65b8167 100644
--- a/board/gcplus/u-boot.lds
+++ b/board/gcplus/u-boot.lds
@@ -37,7 +37,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/gdsys/gdppc440etx/u-boot.lds b/board/gdsys/gdppc440etx/u-boot.lds
index 1df817b..77f0aae 100644
--- a/board/gdsys/gdppc440etx/u-boot.lds
+++ b/board/gdsys/gdppc440etx/u-boot.lds
@@ -76,10 +76,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/gdsys/neo/u-boot.lds b/board/gdsys/neo/u-boot.lds
index d803625..b95eb5c 100644
--- a/board/gdsys/neo/u-boot.lds
+++ b/board/gdsys/neo/u-boot.lds
@@ -67,9 +67,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/gen860t/u-boot-flashenv.lds b/board/gen860t/u-boot-flashenv.lds
index 6c8346a..9785639 100644
--- a/board/gen860t/u-boot-flashenv.lds
+++ b/board/gen860t/u-boot-flashenv.lds
@@ -64,9 +64,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/gen860t/u-boot.lds b/board/gen860t/u-boot.lds
index cab7a10..fbe3c70 100644
--- a/board/gen860t/u-boot.lds
+++ b/board/gen860t/u-boot.lds
@@ -63,10 +63,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/genietv/u-boot.lds b/board/genietv/u-boot.lds
index 3c19d19..ee0b719 100644
--- a/board/genietv/u-boot.lds
+++ b/board/genietv/u-boot.lds
@@ -72,10 +72,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/gth/u-boot.lds b/board/gth/u-boot.lds
index d5df1f4..8826550 100644
--- a/board/gth/u-boot.lds
+++ b/board/gth/u-boot.lds
@@ -62,10 +62,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/gth2/u-boot.lds b/board/gth2/u-boot.lds
index 0594643..e6eee9b 100644
--- a/board/gth2/u-boot.lds
+++ b/board/gth2/u-boot.lds
@@ -38,7 +38,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/hermes/u-boot.lds b/board/hermes/u-boot.lds
index 540e614..02216fb 100644
--- a/board/hermes/u-boot.lds
+++ b/board/hermes/u-boot.lds
@@ -73,10 +73,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/hymod/u-boot.lds b/board/hymod/u-boot.lds
index fdd584d..03fefec 100644
--- a/board/hymod/u-boot.lds
+++ b/board/hymod/u-boot.lds
@@ -75,10 +75,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/icu862/u-boot.lds b/board/icu862/u-boot.lds
index 645baa0..9a28cfd 100644
--- a/board/icu862/u-boot.lds
+++ b/board/icu862/u-boot.lds
@@ -76,10 +76,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/idmr/u-boot.lds b/board/idmr/u-boot.lds
index 0bc7fa1..00c1f2a 100644
--- a/board/idmr/u-boot.lds
+++ b/board/idmr/u-boot.lds
@@ -73,8 +73,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/impa7/u-boot.lds b/board/impa7/u-boot.lds
index a79bb8c..8c9f624 100644
--- a/board/impa7/u-boot.lds
+++ b/board/impa7/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/imx31_litekit/u-boot.lds b/board/imx31_litekit/u-boot.lds
index 9285bd5..f840017 100644
--- a/board/imx31_litekit/u-boot.lds
+++ b/board/imx31_litekit/u-boot.lds
@@ -39,7 +39,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/imx31_phycore/u-boot.lds b/board/imx31_phycore/u-boot.lds
index 9285bd5..f840017 100644
--- a/board/imx31_phycore/u-boot.lds
+++ b/board/imx31_phycore/u-boot.lds
@@ -39,7 +39,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/incaip/u-boot.lds b/board/incaip/u-boot.lds
index da20de1..9a6cd1b 100644
--- a/board/incaip/u-boot.lds
+++ b/board/incaip/u-boot.lds
@@ -38,7 +38,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/innokom/u-boot.lds b/board/innokom/u-boot.lds
index 7cf9fdf..a077bc5 100644
--- a/board/innokom/u-boot.lds
+++ b/board/innokom/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/ip860/u-boot.lds b/board/ip860/u-boot.lds
index d1cb7e2..b47ae8e 100644
--- a/board/ip860/u-boot.lds
+++ b/board/ip860/u-boot.lds
@@ -73,10 +73,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/ivm/u-boot.lds b/board/ivm/u-boot.lds
index 2583a59..ab51bd8 100644
--- a/board/ivm/u-boot.lds
+++ b/board/ivm/u-boot.lds
@@ -62,10 +62,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/ixdp425/u-boot.lds b/board/ixdp425/u-boot.lds
index f46a7c7..7c287e1 100644
--- a/board/ixdp425/u-boot.lds
+++ b/board/ixdp425/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/jse/u-boot.lds b/board/jse/u-boot.lds
index 7141c5a..12d3938 100644
--- a/board/jse/u-boot.lds
+++ b/board/jse/u-boot.lds
@@ -75,10 +75,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/kb9202/u-boot.lds b/board/kb9202/u-boot.lds
index d0666ac..3eae0e2 100644
--- a/board/kb9202/u-boot.lds
+++ b/board/kb9202/u-boot.lds
@@ -37,7 +37,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/keymile/km8xx/km8xx.c b/board/keymile/km8xx/km8xx.c
index 845d3f2..7c58179 100644
--- a/board/keymile/km8xx/km8xx.c
+++ b/board/keymile/km8xx/km8xx.c
@@ -174,6 +174,7 @@ void ft_blob_update (void *blob, bd_t *bd)
ulong memory_data[2] = {0};
ulong flash_data[4] = {0};
ulong flash_reg[3] = {0};
+ uchar enetaddr[6];
memory_data[0] = cpu_to_be32 (bd->bi_memstart);
memory_data[1] = cpu_to_be32 (bd->bi_memsize);
@@ -195,8 +196,9 @@ void ft_blob_update (void *blob, bd_t *bd)
sizeof (brg_data));
/* MAC adr */
+ eth_getenv_enetaddr("ethaddr", enetaddr);
fdt_set_node_and_value (blob, "/soc/cpm/ethernet", "mac-address",
- bd->bi_enetaddr, sizeof (u8) * 6);
+ enetaddr, sizeof (u8) * 6);
}
void ft_board_setup(void *blob, bd_t *bd)
diff --git a/board/keymile/mgcoge/mgcoge.c b/board/keymile/mgcoge/mgcoge.c
index 0e3aa49..67722e7 100644
--- a/board/keymile/mgcoge/mgcoge.c
+++ b/board/keymile/mgcoge/mgcoge.c
@@ -326,6 +326,7 @@ void ft_blob_update (void *blob, bd_t *bd)
ulong memory_data[2] = {0};
ulong flash_data[8] = {0};
flash_info_t *info;
+ uchar enetaddr[6];
memory_data[0] = cpu_to_be32 (bd->bi_memstart);
memory_data[1] = cpu_to_be32 (bd->bi_memsize);
@@ -344,8 +345,9 @@ void ft_blob_update (void *blob, bd_t *bd)
fdt_set_node_and_value (blob, "/localbus", "ranges", flash_data,
sizeof (flash_data));
/* MAC addr */
+ eth_getenv_enetaddr("ethaddr", enetaddr);
fdt_set_node_and_value (blob, "/soc/cpm/ethernet", "mac-address",
- bd->bi_enetaddr, sizeof (u8) * 6);
+ enetaddr, sizeof (u8) * 6);
}
void ft_board_setup (void *blob, bd_t *bd)
diff --git a/board/korat/u-boot-F7FC.lds b/board/korat/u-boot-F7FC.lds
index 9bed401..c175f91f 100644
--- a/board/korat/u-boot-F7FC.lds
+++ b/board/korat/u-boot-F7FC.lds
@@ -75,9 +75,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/korat/u-boot.lds b/board/korat/u-boot.lds
index 05152b7..7798722 100644
--- a/board/korat/u-boot.lds
+++ b/board/korat/u-boot.lds
@@ -75,9 +75,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/kup/common/kup.h b/board/kup/common/kup.h
index 70d7f01..b736283 100644
--- a/board/kup/common/kup.h
+++ b/board/kup/common/kup.h
@@ -41,4 +41,6 @@
extern void poweron_key (void);
+extern void load_sernum_ethaddr(void);
+
#endif /* __KUP_H */
diff --git a/board/kup/kup4k/kup4k.c b/board/kup/kup4k/kup4k.c
index df3ffb4..98f5f5a 100644
--- a/board/kup/kup4k/kup4k.c
+++ b/board/kup/kup4k/kup4k.c
@@ -250,6 +250,7 @@ int misc_init_r (void)
immap->im_ioport.iop_papar &= ~0x80;
immap->im_ioport.iop_padat |= 0x80; /* turn it off */
#endif
+ load_sernum_ethaddr();
setenv("hw","4k");
poweron_key();
return (0);
diff --git a/board/kup/kup4k/u-boot.lds b/board/kup/kup4k/u-boot.lds
index 120ca00..f2b6650 100644
--- a/board/kup/kup4k/u-boot.lds
+++ b/board/kup/kup4k/u-boot.lds
@@ -76,10 +76,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/kup/kup4x/kup4x.c b/board/kup/kup4x/kup4x.c
index c5b742d..65a222b 100644
--- a/board/kup/kup4x/kup4x.c
+++ b/board/kup/kup4x/kup4x.c
@@ -295,7 +295,6 @@ static long int dram_size (long int mamr_value, long int *base,
int misc_init_r (void)
{
volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
-
#ifdef CONFIG_IDE_LED
/* Configure PA8 as output port */
immap->im_ioport.iop_padir |= 0x80;
@@ -306,6 +305,7 @@ int misc_init_r (void)
#ifdef KUP4X_USB
usb_init_kup4x ();
#endif
+ load_sernum_ethaddr();
setenv ("hw", "4x");
poweron_key ();
return (0);
diff --git a/board/kup/kup4x/u-boot.lds b/board/kup/kup4x/u-boot.lds
index 120ca00..f2b6650 100644
--- a/board/kup/kup4x/u-boot.lds
+++ b/board/kup/kup4x/u-boot.lds
@@ -76,10 +76,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/lantec/u-boot.lds b/board/lantec/u-boot.lds
index 6028c26..b9fa2d6 100644
--- a/board/lantec/u-boot.lds
+++ b/board/lantec/u-boot.lds
@@ -73,10 +73,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/lart/u-boot.lds b/board/lart/u-boot.lds
index fce2533..13b7bb7 100644
--- a/board/lart/u-boot.lds
+++ b/board/lart/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/logodl/u-boot.lds b/board/logodl/u-boot.lds
index 7cf9fdf..a077bc5 100644
--- a/board/logodl/u-boot.lds
+++ b/board/logodl/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/lpc2292sodimm/u-boot.lds b/board/lpc2292sodimm/u-boot.lds
index 49d18f7..cb5a3ba 100644
--- a/board/lpc2292sodimm/u-boot.lds
+++ b/board/lpc2292sodimm/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/lpd7a40x/u-boot.lds b/board/lpd7a40x/u-boot.lds
index 3c14437..b98ed95 100644
--- a/board/lpd7a40x/u-boot.lds
+++ b/board/lpd7a40x/u-boot.lds
@@ -37,7 +37,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/lubbock/u-boot.lds b/board/lubbock/u-boot.lds
index 7cf9fdf..a077bc5 100644
--- a/board/lubbock/u-boot.lds
+++ b/board/lubbock/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/lwmon/u-boot.lds b/board/lwmon/u-boot.lds
index 319cc7b..9e46f9d 100644
--- a/board/lwmon/u-boot.lds
+++ b/board/lwmon/u-boot.lds
@@ -62,10 +62,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/lwmon5/u-boot.lds b/board/lwmon5/u-boot.lds
index 05152b7..7798722 100644
--- a/board/lwmon5/u-boot.lds
+++ b/board/lwmon5/u-boot.lds
@@ -75,9 +75,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/m501sk/m501sk.c b/board/m501sk/m501sk.c
index 65a8b29..dc5b786 100644
--- a/board/m501sk/m501sk.c
+++ b/board/m501sk/m501sk.c
@@ -105,11 +105,6 @@ uchar m501sk_gpio_clear(M501SK_PIO io)
return status;
}
-void load_sernum_ethaddr(void)
-{
- return;
-}
-
/*
* Miscelaneous platform dependent initialisations
*/
diff --git a/board/m501sk/u-boot.lds b/board/m501sk/u-boot.lds
index ae6caf5..2247c37 100644
--- a/board/m501sk/u-boot.lds
+++ b/board/m501sk/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/mbx8xx/mbx8xx.c b/board/mbx8xx/mbx8xx.c
index af4f57d..a3bf1f7 100644
--- a/board/mbx8xx/mbx8xx.c
+++ b/board/mbx8xx/mbx8xx.c
@@ -241,7 +241,7 @@ static unsigned int get_reffreq (void)
return *((ulong *) packet->data);
}
-void board_get_enetaddr (uchar * addr)
+static void board_get_enetaddr(uchar *addr)
{
int i;
vpd_packet_t *packet;
@@ -251,6 +251,18 @@ void board_get_enetaddr (uchar * addr)
addr[i] = packet->data[i];
}
+int misc_init_r(void)
+{
+ uchar enetaddr[6];
+
+ if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
+ board_get_enetaddr(enetaddr);
+ eth_putenv_enetaddr("ethaddr", enetaddr);
+ }
+
+ return 0;
+}
+
/*
* Check Board Identity:
*/
diff --git a/board/mbx8xx/u-boot.lds b/board/mbx8xx/u-boot.lds
index 24484c7..ca35e88 100644
--- a/board/mbx8xx/u-boot.lds
+++ b/board/mbx8xx/u-boot.lds
@@ -62,10 +62,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/micronas/vct/u-boot.lds b/board/micronas/vct/u-boot.lds
index da9e605..b90b186 100644
--- a/board/micronas/vct/u-boot.lds
+++ b/board/micronas/vct/u-boot.lds
@@ -35,7 +35,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/mimc/mimc200/u-boot.lds b/board/mimc/mimc200/u-boot.lds
index e736adf..a7243f2 100644
--- a/board/mimc/mimc200/u-boot.lds
+++ b/board/mimc/mimc200/u-boot.lds
@@ -36,8 +36,7 @@ SECTIONS
_etext = .;
.rodata : {
- *(.rodata)
- *(.rodata.*)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
. = ALIGN(8);
diff --git a/board/miromico/hammerhead/u-boot.lds b/board/miromico/hammerhead/u-boot.lds
index e736adf..a7243f2 100644
--- a/board/miromico/hammerhead/u-boot.lds
+++ b/board/miromico/hammerhead/u-boot.lds
@@ -36,8 +36,7 @@ SECTIONS
_etext = .;
.rodata : {
- *(.rodata)
- *(.rodata.*)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
. = ALIGN(8);
diff --git a/board/ml2/u-boot.lds b/board/ml2/u-boot.lds
index 13ceea0..a6b6748 100644
--- a/board/ml2/u-boot.lds
+++ b/board/ml2/u-boot.lds
@@ -79,10 +79,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/modnet50/u-boot.lds b/board/modnet50/u-boot.lds
index a435466..b72e126 100644
--- a/board/modnet50/u-boot.lds
+++ b/board/modnet50/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/mousse/u-boot.lds b/board/mousse/u-boot.lds
index 8188873..44144e2 100644
--- a/board/mousse/u-boot.lds
+++ b/board/mousse/u-boot.lds
@@ -62,10 +62,8 @@ SECTIONS
*(.fixup)
*(.got1)
. = ALIGN(16);
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/mp2usb/u-boot.lds b/board/mp2usb/u-boot.lds
index d0666ac..3eae0e2 100644
--- a/board/mp2usb/u-boot.lds
+++ b/board/mp2usb/u-boot.lds
@@ -37,7 +37,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/mpc8540eval/u-boot.lds b/board/mpc8540eval/u-boot.lds
index d65ccbe..0747913 100644
--- a/board/mpc8540eval/u-boot.lds
+++ b/board/mpc8540eval/u-boot.lds
@@ -73,10 +73,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/mpl/mip405/u-boot.lds b/board/mpl/mip405/u-boot.lds
index 8714c2b..d71a299 100644
--- a/board/mpl/mip405/u-boot.lds
+++ b/board/mpl/mip405/u-boot.lds
@@ -89,10 +89,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/mpl/pip405/u-boot.lds b/board/mpl/pip405/u-boot.lds
index afe203b..f6f88a7 100644
--- a/board/mpl/pip405/u-boot.lds
+++ b/board/mpl/pip405/u-boot.lds
@@ -84,10 +84,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/mpl/vcma9/cmd_vcma9.c b/board/mpl/vcma9/cmd_vcma9.c
index 2748fa9..7d2aa3c 100644
--- a/board/mpl/vcma9/cmd_vcma9.c
+++ b/board/mpl/vcma9/cmd_vcma9.c
@@ -76,21 +76,18 @@ int do_vcma9(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
cs8900_e2prom_write(addr, data);
} else if (strcmp(argv[2], "setaddr") == 0) {
uchar addr, i, csum; ushort data;
+ uchar ethaddr[6];
/* check for valid ethaddr */
- for (i = 0; i < 6; i++)
- if (gd->bd->bi_enetaddr[i] != 0)
- break;
-
- if (i < 6) {
+ if (eth_getenv_enetaddr("ethaddr", ethaddr)) {
addr = 1;
data = 0x2158;
cs8900_e2prom_write(addr, data);
csum = cs8900_chksum(data);
addr++;
for (i = 0; i < 6; i+=2) {
- data = gd->bd->bi_enetaddr[i+1] << 8 |
- gd->bd->bi_enetaddr[i];
+ data = enetaddr[i+1] << 8 |
+ enetaddr[i];
cs8900_e2prom_write(addr, data);
csum += cs8900_chksum(data);
addr++;
diff --git a/board/mpl/vcma9/u-boot.lds b/board/mpl/vcma9/u-boot.lds
index 987b07d..33363c2 100644
--- a/board/mpl/vcma9/u-boot.lds
+++ b/board/mpl/vcma9/u-boot.lds
@@ -37,7 +37,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/mpr2/u-boot.lds b/board/mpr2/u-boot.lds
index b1f0e1d..deae344 100644
--- a/board/mpr2/u-boot.lds
+++ b/board/mpr2/u-boot.lds
@@ -63,7 +63,7 @@ SECTIONS
PROVIDE (_ecode = .);
.rodata :
{
- *(.rodata)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
. = ALIGN(4);
}
PROVIDE (_etext = .);
diff --git a/board/ms7720se/u-boot.lds b/board/ms7720se/u-boot.lds
index 2156f6a..1f9b792 100644
--- a/board/ms7720se/u-boot.lds
+++ b/board/ms7720se/u-boot.lds
@@ -62,7 +62,7 @@ SECTIONS
PROVIDE (_ecode = .);
.rodata :
{
- *(.rodata)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
. = ALIGN(4);
}
PROVIDE (_etext = .);
diff --git a/board/ms7722se/u-boot.lds b/board/ms7722se/u-boot.lds
index 7dffe00..7b0fb67 100644
--- a/board/ms7722se/u-boot.lds
+++ b/board/ms7722se/u-boot.lds
@@ -59,7 +59,7 @@ SECTIONS
PROVIDE (_ecode = .);
.rodata :
{
- *(.rodata)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
. = ALIGN(4);
}
PROVIDE (_etext = .);
diff --git a/board/ms7750se/u-boot.lds b/board/ms7750se/u-boot.lds
index 7dffe00..7b0fb67 100644
--- a/board/ms7750se/u-boot.lds
+++ b/board/ms7750se/u-boot.lds
@@ -59,7 +59,7 @@ SECTIONS
PROVIDE (_ecode = .);
.rodata :
{
- *(.rodata)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
. = ALIGN(4);
}
PROVIDE (_etext = .);
diff --git a/board/muas3001/muas3001.c b/board/muas3001/muas3001.c
index 6b1e59f..8f83dd9 100644
--- a/board/muas3001/muas3001.c
+++ b/board/muas3001/muas3001.c
@@ -346,7 +346,9 @@ void ft_blob_update (void *blob, bd_t *bd)
/* MAC Adresse */
nodeoffset = fdt_path_offset (blob, "/soc/cpm/ethernet");
if (nodeoffset >= 0) {
- ret = fdt_setprop (blob, nodeoffset, "mac-address", bd->bi_enetaddr,
+ uchar ethaddr[6];
+ eth_getenv_enetaddr("ethaddr", ethaddr);
+ ret = fdt_setprop (blob, nodeoffset, "mac-address", ethaddr,
sizeof (uchar) * 6);
if (ret < 0)
printf ("ft_blob_update): cannot set /soc/cpm/ethernet/mac-address "
diff --git a/board/munices/u-boot.lds b/board/munices/u-boot.lds
index 0a1a6ad..5fe8707 100644
--- a/board/munices/u-boot.lds
+++ b/board/munices/u-boot.lds
@@ -57,9 +57,7 @@ SECTIONS
*(.fixup)
*(.got1)
. = ALIGN(16);
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/mx1ads/u-boot.lds b/board/mx1ads/u-boot.lds
index 5460c8c..1c710cb 100644
--- a/board/mx1ads/u-boot.lds
+++ b/board/mx1ads/u-boot.lds
@@ -38,7 +38,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/mx1fs2/u-boot.lds b/board/mx1fs2/u-boot.lds
index c96e58a..d912d93 100644
--- a/board/mx1fs2/u-boot.lds
+++ b/board/mx1fs2/u-boot.lds
@@ -37,7 +37,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/nc650/u-boot.lds b/board/nc650/u-boot.lds
index ca91ac4..dd040f0 100644
--- a/board/nc650/u-boot.lds
+++ b/board/nc650/u-boot.lds
@@ -61,10 +61,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/netphone/u-boot.lds b/board/netphone/u-boot.lds
index 8836560..68fe165 100644
--- a/board/netphone/u-boot.lds
+++ b/board/netphone/u-boot.lds
@@ -73,10 +73,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/netstal/common/nm_bsp.c b/board/netstal/common/nm_bsp.c
index e38b706..237f4ed 100644
--- a/board/netstal/common/nm_bsp.c
+++ b/board/netstal/common/nm_bsp.c
@@ -83,40 +83,20 @@ void set_params_for_sw_install(int install_requested, char *board_name )
void common_misc_init_r(void)
{
- char *s = getenv(DEFAULT_ETH_ADDR);
- char *e;
- int i;
- u32 serial = get_serial_number();
IPaddr_t ipaddr;
char *ipstring;
+ uchar ethaddr[6];
- for (i = 0; i < 6; ++i) {
- gd->bd->bi_enetaddr[i] = s ? simple_strtoul(s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
-
- if (gd->bd->bi_enetaddr[3] == 0 &&
- gd->bd->bi_enetaddr[4] == 0 &&
- gd->bd->bi_enetaddr[5] == 0) {
- char ethaddr[22];
-
+ if (!eth_getenv_enetaddr(DEFAULT_ETH_ADDR, ethaddr)) {
/* Must be in sync with CONFIG_ETHADDR */
- gd->bd->bi_enetaddr[0] = 0x00;
- gd->bd->bi_enetaddr[1] = 0x60;
- gd->bd->bi_enetaddr[2] = 0x13;
- gd->bd->bi_enetaddr[3] = (serial >> 16) & 0xff;
- gd->bd->bi_enetaddr[4] = (serial >> 8) & 0xff;
- gd->bd->bi_enetaddr[5] = hcu_get_slot();
- sprintf(ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X%c",
- gd->bd->bi_enetaddr[0], gd->bd->bi_enetaddr[1],
- gd->bd->bi_enetaddr[2], gd->bd->bi_enetaddr[3],
- gd->bd->bi_enetaddr[4],
- gd->bd->bi_enetaddr[5],
- 0) ;
- printf("%s: Setting eth %s serial 0x%x\n", __FUNCTION__,
- ethaddr, serial);
- setenv(DEFAULT_ETH_ADDR, ethaddr);
+ u32 serial = get_serial_number();
+ ethaddr[0] = 0x00;
+ ethaddr[1] = 0x60;
+ ethaddr[2] = 0x13;
+ ethaddr[3] = (serial >> 16) & 0xff;
+ ethaddr[4] = (serial >> 8) & 0xff;
+ ethaddr[5] = hcu_get_slot();
+ eth_setenv_enetaddr(DEFAULT_ETH_ADDR, ethaddr);
}
/* IP-Adress update */
diff --git a/board/netstal/hcu4/u-boot.lds b/board/netstal/hcu4/u-boot.lds
index d9abcd6..0c38ea2 100644
--- a/board/netstal/hcu4/u-boot.lds
+++ b/board/netstal/hcu4/u-boot.lds
@@ -72,10 +72,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/netstal/hcu5/u-boot.lds b/board/netstal/hcu5/u-boot.lds
index c3009bb..21a2be2 100644
--- a/board/netstal/hcu5/u-boot.lds
+++ b/board/netstal/hcu5/u-boot.lds
@@ -74,9 +74,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/netstal/mcu25/u-boot.lds b/board/netstal/mcu25/u-boot.lds
index a00f570..b589956 100644
--- a/board/netstal/mcu25/u-boot.lds
+++ b/board/netstal/mcu25/u-boot.lds
@@ -72,10 +72,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/netstar/eeprom.lds b/board/netstar/eeprom.lds
index f3be320..132476d 100644
--- a/board/netstar/eeprom.lds
+++ b/board/netstar/eeprom.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/netstar/u-boot.lds b/board/netstar/u-boot.lds
index 5823f62..6a5510a 100644
--- a/board/netstar/u-boot.lds
+++ b/board/netstar/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/netta/u-boot.lds b/board/netta/u-boot.lds
index 4966f4d..14201ac 100644
--- a/board/netta/u-boot.lds
+++ b/board/netta/u-boot.lds
@@ -73,10 +73,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/netta2/u-boot.lds b/board/netta2/u-boot.lds
index 4966f4d..14201ac 100644
--- a/board/netta2/u-boot.lds
+++ b/board/netta2/u-boot.lds
@@ -73,10 +73,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/netvia/u-boot.lds b/board/netvia/u-boot.lds
index 6bc5768..8c48f1f 100644
--- a/board/netvia/u-boot.lds
+++ b/board/netvia/u-boot.lds
@@ -73,10 +73,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/ns9750dev/u-boot.lds b/board/ns9750dev/u-boot.lds
index c656701..b7fc19c 100644
--- a/board/ns9750dev/u-boot.lds
+++ b/board/ns9750dev/u-boot.lds
@@ -37,7 +37,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/nx823/flash.c b/board/nx823/flash.c
index 194d841..336e704 100644
--- a/board/nx823/flash.c
+++ b/board/nx823/flash.c
@@ -27,8 +27,9 @@
#include <common.h>
#include <mpc8xx.h>
+DECLARE_GLOBAL_DATA_PTR;
+
flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
-extern u_long *my_sernum; /* from nx823.c */
/*-----------------------------------------------------------------------
* Protection Flags:
@@ -346,7 +347,7 @@ int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
if (addr >= CONFIG_SYS_FLASH_SN_SECTOR && addr < CONFIG_SYS_FLASH_SN_BASE)
{
u_long dest = CONFIG_SYS_FLASH_SN_BASE;
- u_short *sn = (u_short *)my_sernum;
+ u_short *sn = (u_short *)gd->bd->bi_sernum;
printf("(saving sernum)");
for (i=0; i<4; i++)
diff --git a/board/nx823/nx823.c b/board/nx823/nx823.c
index df9aaab..6ec29dc 100644
--- a/board/nx823/nx823.c
+++ b/board/nx823/nx823.c
@@ -360,39 +360,30 @@ static long int dram_size (long int mamr_value, long int *base,
return (get_ram_size (base, maxsize));
}
-u_long *my_sernum;
-
int misc_init_r (void)
{
+ int i;
char tmp[50];
- u_char *e = gd->bd->bi_enetaddr;
+ uchar ethaddr[6];
+ bd_t *bd = gd->bd;
+ ulong my_sernum = bd->bi_sernum;
- /* save serial numbre from flash (uniquely programmed) */
- my_sernum = malloc (8);
- memcpy (my_sernum, gd->bd->bi_sernum, 8);
+ /* load unique serial number */
+ for (i = 0; i < 8; ++i)
+ bd->bi_sernum[i] = *(u_char *) (CONFIG_SYS_FLASH_SN_BASE + i);
/* save env variables according to sernum */
sprintf (tmp, "%08lx%08lx", my_sernum[0], my_sernum[1]);
setenv ("serial#", tmp);
- sprintf (tmp, "%02x:%02x:%02x:%02x:%02x:%02x", e[0], e[1], e[2], e[3],
- e[4], e[5]);
- setenv ("ethaddr", tmp);
- return (0);
-}
-
-void load_sernum_ethaddr (void)
-{
- int i;
- bd_t *bd = gd->bd;
-
- for (i = 0; i < 8; i++) {
- bd->bi_sernum[i] = *(u_char *) (CONFIG_SYS_FLASH_SN_BASE + i);
+ if (!eth_getenv_enetaddr("ethaddr", ethaddr)) {
+ ethaddr[0] = 0x10;
+ ethaddr[1] = 0x20;
+ ethaddr[2] = 0x30;
+ ethaddr[3] = bd->bi_sernum[1] << 4 | bd->bi_sernum[2];
+ ethaddr[4] = bd->bi_sernum[5];
+ ethaddr[5] = bd->bi_sernum[6];
}
- bd->bi_enetaddr[0] = 0x10;
- bd->bi_enetaddr[1] = 0x20;
- bd->bi_enetaddr[2] = 0x30;
- bd->bi_enetaddr[3] = bd->bi_sernum[1] << 4 | bd->bi_sernum[2];
- bd->bi_enetaddr[4] = bd->bi_sernum[5];
- bd->bi_enetaddr[5] = bd->bi_sernum[6];
+
+ return 0;
}
diff --git a/board/nx823/u-boot.lds b/board/nx823/u-boot.lds
index 759b412..ee74eb9 100644
--- a/board/nx823/u-boot.lds
+++ b/board/nx823/u-boot.lds
@@ -63,10 +63,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/omap1510inn/u-boot.lds b/board/omap1510inn/u-boot.lds
index 1c70fcd..13b3643 100644
--- a/board/omap1510inn/u-boot.lds
+++ b/board/omap1510inn/u-boot.lds
@@ -37,7 +37,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/omap1610inn/u-boot.lds b/board/omap1610inn/u-boot.lds
index d86eb36..4d50f2c 100644
--- a/board/omap1610inn/u-boot.lds
+++ b/board/omap1610inn/u-boot.lds
@@ -34,7 +34,7 @@ SECTIONS
*(.text)
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
diff --git a/board/omap2420h4/u-boot.lds b/board/omap2420h4/u-boot.lds
index 89e627b..46535dd 100644
--- a/board/omap2420h4/u-boot.lds
+++ b/board/omap2420h4/u-boot.lds
@@ -39,7 +39,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/omap3/beagle/u-boot.lds b/board/omap3/beagle/u-boot.lds
index 69d8ac9..66a8925 100644
--- a/board/omap3/beagle/u-boot.lds
+++ b/board/omap3/beagle/u-boot.lds
@@ -39,7 +39,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) }
__exidx_start = .;
diff --git a/board/omap3/evm/u-boot.lds b/board/omap3/evm/u-boot.lds
index 69d8ac9..66a8925 100644
--- a/board/omap3/evm/u-boot.lds
+++ b/board/omap3/evm/u-boot.lds
@@ -39,7 +39,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) }
__exidx_start = .;
diff --git a/board/omap3/overo/u-boot.lds b/board/omap3/overo/u-boot.lds
index 69d8ac9..66a8925 100644
--- a/board/omap3/overo/u-boot.lds
+++ b/board/omap3/overo/u-boot.lds
@@ -39,7 +39,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) }
__exidx_start = .;
diff --git a/board/omap3/pandora/u-boot.lds b/board/omap3/pandora/u-boot.lds
index 69d8ac9..66a8925 100644
--- a/board/omap3/pandora/u-boot.lds
+++ b/board/omap3/pandora/u-boot.lds
@@ -39,7 +39,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) }
__exidx_start = .;
diff --git a/board/omap3/zoom1/u-boot.lds b/board/omap3/zoom1/u-boot.lds
index 01047c3..0eb318b 100644
--- a/board/omap3/zoom1/u-boot.lds
+++ b/board/omap3/zoom1/u-boot.lds
@@ -39,7 +39,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) }
__exidx_start = .;
diff --git a/board/omap5912osk/u-boot.lds b/board/omap5912osk/u-boot.lds
index 0bf6eff..3132b9a 100644
--- a/board/omap5912osk/u-boot.lds
+++ b/board/omap5912osk/u-boot.lds
@@ -34,7 +34,7 @@ SECTIONS
*(.text)
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
diff --git a/board/omap730p2/u-boot.lds b/board/omap730p2/u-boot.lds
index d86eb36..4d50f2c 100644
--- a/board/omap730p2/u-boot.lds
+++ b/board/omap730p2/u-boot.lds
@@ -34,7 +34,7 @@ SECTIONS
*(.text)
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
diff --git a/board/pb1x00/u-boot.lds b/board/pb1x00/u-boot.lds
index da20de1..9a6cd1b 100644
--- a/board/pb1x00/u-boot.lds
+++ b/board/pb1x00/u-boot.lds
@@ -38,7 +38,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/pcippc2/u-boot.lds b/board/pcippc2/u-boot.lds
index 5395108..4bb582d 100644
--- a/board/pcippc2/u-boot.lds
+++ b/board/pcippc2/u-boot.lds
@@ -73,10 +73,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/pcs440ep/pcs440ep.c b/board/pcs440ep/pcs440ep.c
index 5fd3291..2727214 100644
--- a/board/pcs440ep/pcs440ep.c
+++ b/board/pcs440ep/pcs440ep.c
@@ -182,14 +182,21 @@ int board_early_init_f(void)
}
#define EEPROM_LEN 256
-void load_sernum_ethaddr (void)
+static void load_ethaddr(void)
{
+ int ok_ethaddr, ok_eth1addr;
int ret;
char buf[EEPROM_LEN];
char mac[32];
char *use_eeprom;
u16 checksumcrc16 = 0;
+ /* If the env is sane, then nothing for us to do */
+ ok_ethaddr = eth_getenv_enetaddr("ethaddr", buf);
+ ok_eth1addr = eth_getenv_enetaddr("eth1addr", buf);
+ if (ok_ethaddr && ok_eth1addr)
+ return;
+
/* read the MACs from EEprom */
status_led_set (0, STATUS_LED_ON);
status_led_set (1, STATUS_LED_ON);
@@ -207,22 +214,10 @@ void load_sernum_ethaddr (void)
printf("%s: EEPROM Checksum not OK\n", __FUNCTION__);
} else {
/* get the MACs */
- sprintf (mac, "%02x:%02x:%02x:%02x:%02x:%02x",
- buf[3],
- buf[4],
- buf[5],
- buf[6],
- buf[7],
- buf[8]);
- setenv ("ethaddr", (char *) mac);
- sprintf (mac, "%02x:%02x:%02x:%02x:%02x:%02x",
- buf[9],
- buf[10],
- buf[11],
- buf[12],
- buf[13],
- buf[14]);
- setenv ("eth1addr", (char *) mac);
+ if (!ok_ethaddr)
+ eth_setenv_enetaddr("ethaddr", &buf[3]);
+ if (!ok_eth1addr)
+ eth_setenv_enetaddr("eth1addr", &buf[9]);
return;
}
}
@@ -446,6 +441,8 @@ int misc_init_r (void)
uint pbcr;
int size_val = 0;
+ load_ethaddr();
+
/* Re-do sizing to get full correct info */
mtdcr(ebccfga, pb0cr);
pbcr = mfdcr(ebccfgd);
diff --git a/board/pcs440ep/u-boot.lds b/board/pcs440ep/u-boot.lds
index 6b7dd21..a4c537e 100644
--- a/board/pcs440ep/u-boot.lds
+++ b/board/pcs440ep/u-boot.lds
@@ -74,10 +74,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/pleb2/u-boot.lds b/board/pleb2/u-boot.lds
index 7cf9fdf..a077bc5 100644
--- a/board/pleb2/u-boot.lds
+++ b/board/pleb2/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/pm854/u-boot.lds b/board/pm854/u-boot.lds
index 18cb27a..45aaadc 100644
--- a/board/pm854/u-boot.lds
+++ b/board/pm854/u-boot.lds
@@ -81,10 +81,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/pm856/u-boot.lds b/board/pm856/u-boot.lds
index e9c6a12..1dce2ab 100644
--- a/board/pm856/u-boot.lds
+++ b/board/pm856/u-boot.lds
@@ -81,10 +81,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/pn62/pn62.c b/board/pn62/pn62.c
index 1b545bf..53d7e57 100644
--- a/board/pn62/pn62.c
+++ b/board/pn62/pn62.c
@@ -30,7 +30,7 @@
DECLARE_GLOBAL_DATA_PTR;
static int get_serial_number (char *string, int size);
-static int get_mac_address (int id, u8 * mac, char *string, int size);
+static void get_mac_address(int id, u8 *mac);
#ifdef CONFIG_SHOW_BOOT_PROGRESS
void show_boot_progress (int phase)
@@ -138,18 +138,16 @@ int misc_init_r (void)
}
show_startup_phase (9);
- if (getenv ("ethaddr") == NULL &&
- get_mac_address (0, mac, str, sizeof (str)) > 0) {
- setenv ("ethaddr", str);
- memcpy (gd->bd->bi_enetaddr, mac, 6);
+ if (!eth_getenv_enetaddr("ethaddr", mac)) {
+ get_mac_address(0, mac);
+ eth_setenv_enetaddr("ethaddr", mac);
}
show_startup_phase (10);
#ifdef CONFIG_HAS_ETH1
- if (getenv ("eth1addr") == NULL &&
- get_mac_address (1, mac, str, sizeof (str)) > 0) {
- setenv ("eth1addr", str);
- memcpy (gd->bd->bi_enet1addr, mac, 6);
+ if (!eth_getenv_enetaddr("eth1addr", mac)) {
+ get_mac_address(1, mac);
+ eth_setenv_enetaddr("eth1addr", mac);
}
#endif /* CONFIG_HAS_ETH1 */
show_startup_phase (11);
@@ -177,15 +175,9 @@ static int get_serial_number (char *string, int size)
return i;
}
-static int get_mac_address (int id, u8 * mac, char *string, int size)
+static void get_mac_address(int id, u8 *mac)
{
- if (size < 6 * 3)
- return -1;
-
i2155x_read_vpd (I2155X_VPD_MAC0_START + 6 * id, 6, mac);
- return sprintf (string, "%02x:%02x:%02x:%02x:%02x:%02x",
- mac[0], mac[1], mac[2],
- mac[3], mac[4], mac[5]);
}
int board_eth_init(bd_t *bis)
diff --git a/board/ppmc7xx/u-boot.lds b/board/ppmc7xx/u-boot.lds
index ca2e300..b0da216 100644
--- a/board/ppmc7xx/u-boot.lds
+++ b/board/ppmc7xx/u-boot.lds
@@ -70,9 +70,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/prodrive/alpr/u-boot.lds b/board/prodrive/alpr/u-boot.lds
index 33b03af..e7c5fe6 100644
--- a/board/prodrive/alpr/u-boot.lds
+++ b/board/prodrive/alpr/u-boot.lds
@@ -76,10 +76,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/prodrive/p3mx/u-boot.lds b/board/prodrive/p3mx/u-boot.lds
index ff2d8b7..632921a 100644
--- a/board/prodrive/p3mx/u-boot.lds
+++ b/board/prodrive/p3mx/u-boot.lds
@@ -70,10 +70,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/prodrive/p3p440/u-boot.lds b/board/prodrive/p3p440/u-boot.lds
index 17cfde8..9327970 100644
--- a/board/prodrive/p3p440/u-boot.lds
+++ b/board/prodrive/p3p440/u-boot.lds
@@ -76,10 +76,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/prodrive/pdnb3/u-boot.lds b/board/prodrive/pdnb3/u-boot.lds
index dc59119..6324436 100644
--- a/board/prodrive/pdnb3/u-boot.lds
+++ b/board/prodrive/pdnb3/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/psyent/pci5441/u-boot.lds b/board/psyent/pci5441/u-boot.lds
index d3b7c31..b2d88a5 100644
--- a/board/psyent/pci5441/u-boot.lds
+++ b/board/psyent/pci5441/u-boot.lds
@@ -34,8 +34,7 @@ SECTIONS
*(.text)
*(.text.*)
*(.gnu.linkonce.t*)
- *(.rodata)
- *(.rodata.*)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
*(.gnu.linkonce.r*)
}
. = ALIGN (4);
diff --git a/board/psyent/pk1c20/u-boot.lds b/board/psyent/pk1c20/u-boot.lds
index d3b7c31..b2d88a5 100644
--- a/board/psyent/pk1c20/u-boot.lds
+++ b/board/psyent/pk1c20/u-boot.lds
@@ -34,8 +34,7 @@ SECTIONS
*(.text)
*(.text.*)
*(.gnu.linkonce.t*)
- *(.rodata)
- *(.rodata.*)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
*(.gnu.linkonce.r*)
}
. = ALIGN (4);
diff --git a/board/purple/u-boot.lds b/board/purple/u-boot.lds
index bf1394b..04a641a 100644
--- a/board/purple/u-boot.lds
+++ b/board/purple/u-boot.lds
@@ -48,7 +48,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/pxa255_idp/u-boot.lds b/board/pxa255_idp/u-boot.lds
index 96ac25c..fb4358b 100644
--- a/board/pxa255_idp/u-boot.lds
+++ b/board/pxa255_idp/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/qemu-mips/u-boot.lds b/board/qemu-mips/u-boot.lds
index 03bcb09..ad058ca 100644
--- a/board/qemu-mips/u-boot.lds
+++ b/board/qemu-mips/u-boot.lds
@@ -38,7 +38,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/quad100hd/u-boot.lds b/board/quad100hd/u-boot.lds
index 7cf4d4f..24d31a1 100644
--- a/board/quad100hd/u-boot.lds
+++ b/board/quad100hd/u-boot.lds
@@ -68,9 +68,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/quantum/u-boot.lds b/board/quantum/u-boot.lds
index 55cb5ec..faa1c6c 100644
--- a/board/quantum/u-boot.lds
+++ b/board/quantum/u-boot.lds
@@ -74,10 +74,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/r360mpi/u-boot.lds b/board/r360mpi/u-boot.lds
index db28544..61d4b11 100644
--- a/board/r360mpi/u-boot.lds
+++ b/board/r360mpi/u-boot.lds
@@ -71,10 +71,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/rbc823/u-boot.lds b/board/rbc823/u-boot.lds
index 63bd21b..552f15d 100644
--- a/board/rbc823/u-boot.lds
+++ b/board/rbc823/u-boot.lds
@@ -73,10 +73,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/renesas/MigoR/u-boot.lds b/board/renesas/MigoR/u-boot.lds
index f9c1eff..c004b83 100644
--- a/board/renesas/MigoR/u-boot.lds
+++ b/board/renesas/MigoR/u-boot.lds
@@ -59,7 +59,7 @@ SECTIONS
PROVIDE (_ecode = .);
.rodata :
{
- *(.rodata)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
. = ALIGN(4);
}
PROVIDE (_etext = .);
diff --git a/board/renesas/ap325rxa/u-boot.lds b/board/renesas/ap325rxa/u-boot.lds
index e9f8dc0..94bacca 100644
--- a/board/renesas/ap325rxa/u-boot.lds
+++ b/board/renesas/ap325rxa/u-boot.lds
@@ -59,7 +59,7 @@ SECTIONS
PROVIDE (_ecode = .);
.rodata :
{
- *(.rodata)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
. = ALIGN(4);
}
PROVIDE (_etext = .);
diff --git a/board/renesas/r2dplus/u-boot.lds b/board/renesas/r2dplus/u-boot.lds
index 040e530..e1c15b0 100644
--- a/board/renesas/r2dplus/u-boot.lds
+++ b/board/renesas/r2dplus/u-boot.lds
@@ -59,7 +59,7 @@ SECTIONS
PROVIDE (_ecode = .);
.rodata :
{
- *(.rodata)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
. = ALIGN(4);
}
PROVIDE (_etext = .);
diff --git a/board/renesas/r7780mp/u-boot.lds b/board/renesas/r7780mp/u-boot.lds
index eaa05d0..f32d0b8 100644
--- a/board/renesas/r7780mp/u-boot.lds
+++ b/board/renesas/r7780mp/u-boot.lds
@@ -59,7 +59,7 @@ SECTIONS
PROVIDE (_ecode = .);
.rodata :
{
- *(.rodata)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
. = ALIGN(4);
}
PROVIDE (_etext = .);
diff --git a/board/renesas/rsk7203/u-boot.lds b/board/renesas/rsk7203/u-boot.lds
index 63e5b97..bd4a550 100644
--- a/board/renesas/rsk7203/u-boot.lds
+++ b/board/renesas/rsk7203/u-boot.lds
@@ -56,7 +56,7 @@ SECTIONS
PROVIDE (_ecode = .);
.rodata :
{
- *(.rodata)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
. = ALIGN(4);
}
PROVIDE (_etext = .);
diff --git a/board/renesas/sh7763rdp/u-boot.lds b/board/renesas/sh7763rdp/u-boot.lds
index 7177416..b1a967d 100644
--- a/board/renesas/sh7763rdp/u-boot.lds
+++ b/board/renesas/sh7763rdp/u-boot.lds
@@ -59,7 +59,7 @@ SECTIONS
PROVIDE (_ecode = .);
.rodata :
{
- *(.rodata)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
. = ALIGN(4);
}
PROVIDE (_etext = .);
diff --git a/board/renesas/sh7785lcr/u-boot.lds b/board/renesas/sh7785lcr/u-boot.lds
index 446fb93..255ab37 100644
--- a/board/renesas/sh7785lcr/u-boot.lds
+++ b/board/renesas/sh7785lcr/u-boot.lds
@@ -50,7 +50,7 @@ SECTIONS
PROVIDE (_ecode = .);
.rodata :
{
- *(.rodata)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
. = ALIGN(4);
}
PROVIDE (_etext = .);
diff --git a/board/rmu/u-boot.lds b/board/rmu/u-boot.lds
index 55cb5ec..faa1c6c 100644
--- a/board/rmu/u-boot.lds
+++ b/board/rmu/u-boot.lds
@@ -74,10 +74,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/rsdproto/u-boot.lds b/board/rsdproto/u-boot.lds
index b2bd576..771f7de 100644
--- a/board/rsdproto/u-boot.lds
+++ b/board/rsdproto/u-boot.lds
@@ -62,10 +62,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/samsung/smdk2400/u-boot.lds b/board/samsung/smdk2400/u-boot.lds
index 987b07d..33363c2 100644
--- a/board/samsung/smdk2400/u-boot.lds
+++ b/board/samsung/smdk2400/u-boot.lds
@@ -37,7 +37,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/samsung/smdk2410/u-boot.lds b/board/samsung/smdk2410/u-boot.lds
index 987b07d..33363c2 100644
--- a/board/samsung/smdk2410/u-boot.lds
+++ b/board/samsung/smdk2410/u-boot.lds
@@ -37,7 +37,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/samsung/smdk6400/u-boot-nand.lds b/board/samsung/smdk6400/u-boot-nand.lds
index bd6b24f..b868fdd 100644
--- a/board/samsung/smdk6400/u-boot-nand.lds
+++ b/board/samsung/smdk6400/u-boot-nand.lds
@@ -40,7 +40,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/sandburst/common/sb_common.c b/board/sandburst/common/sb_common.c
index f6ea16f..b8160c8 100644
--- a/board/sandburst/common/sb_common.c
+++ b/board/sandburst/common/sb_common.c
@@ -394,9 +394,8 @@ int is_pci_host(struct pci_controller *hose)
* mgmt mac address.
*
************************************************************************/
-static int macaddr_idx = 0;
-void board_get_enetaddr (uchar * enet)
+void board_get_enetaddr(int macaddr_idx, uchar *enet)
{
int i;
unsigned short tmp;
@@ -419,7 +418,6 @@ void board_get_enetaddr (uchar * enet)
tmp += 31;
memcpy(&enet[4], &tmp, 2);
- macaddr_idx++;
} else {
enet[0] = 0x02;
enet[1] = 0x00;
diff --git a/board/sandburst/common/sb_common.h b/board/sandburst/common/sb_common.h
index 888e4f0..e652ba8 100644
--- a/board/sandburst/common/sb_common.h
+++ b/board/sandburst/common/sb_common.h
@@ -72,5 +72,6 @@ int sbcommon_get_master(void);
int sbcommon_secondary_present(void);
unsigned short sbcommon_get_serial_number(void);
void sbcommon_fans(void);
+void board_get_enetaddr(int macaddr_idx, uchar *enet);
#endif /* __SBCOMMON_H__ */
diff --git a/board/sandburst/karef/karef.c b/board/sandburst/karef/karef.c
index 9b94af5..55310d7 100644
--- a/board/sandburst/karef/karef.c
+++ b/board/sandburst/karef/karef.c
@@ -354,6 +354,7 @@ int misc_init_r (void)
{
unsigned short sernum;
char envstr[255];
+ uchar enetaddr[6];
KAREF_FPGA_REGS_ST *karef_ps;
OFEM_FPGA_REGS_ST *ofem_ps;
@@ -408,6 +409,34 @@ int misc_init_r (void)
printf("fakeled is set. use 'setenv fakeled ; setenv bootdelay 5 ; saveenv' to recover\n");
}
+#ifdef CONFIG_HAS_ETH0
+ if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
+ board_get_enetaddr(0, enetaddr);
+ eth_putenv_enetaddr("ethaddr", enetaddr);
+ }
+#endif
+
+#ifdef CONFIG_HAS_ETH1
+ if (!eth_getenv_enetaddr("eth1addr", enetaddr)) {
+ board_get_enetaddr(1, enetaddr);
+ eth_putenv_enetaddr("eth1addr", enetaddr);
+ }
+#endif
+
+#ifdef CONFIG_HAS_ETH2
+ if (!eth_getenv_enetaddr("eth2addr", enetaddr)) {
+ board_get_enetaddr(2, enetaddr);
+ eth_putenv_enetaddr("eth2addr", enetaddr);
+ }
+#endif
+
+#ifdef CONFIG_HAS_ETH3
+ if (!eth_getenv_enetaddr("eth3addr", enetaddr)) {
+ board_get_enetaddr(3, enetaddr);
+ eth_putenv_enetaddr("eth3addr", enetaddr);
+ }
+#endif
+
return (0);
}
diff --git a/board/sandburst/karef/u-boot.lds b/board/sandburst/karef/u-boot.lds
index 6223f4e..f509100 100644
--- a/board/sandburst/karef/u-boot.lds
+++ b/board/sandburst/karef/u-boot.lds
@@ -91,10 +91,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/sandburst/metrobox/metrobox.c b/board/sandburst/metrobox/metrobox.c
index ec4c451..8bb8c02 100644
--- a/board/sandburst/metrobox/metrobox.c
+++ b/board/sandburst/metrobox/metrobox.c
@@ -321,6 +321,7 @@ int misc_init_r (void)
{
unsigned short sernum;
char envstr[255];
+ uchar enetaddr[6];
unsigned char opto_rev;
OPTO_FPGA_REGS_ST *opto_ps;
@@ -379,6 +380,34 @@ int misc_init_r (void)
}
}
+#ifdef CONFIG_HAS_ETH0
+ if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
+ board_get_enetaddr(0, enetaddr);
+ eth_putenv_enetaddr("ethaddr", enetaddr);
+ }
+#endif
+
+#ifdef CONFIG_HAS_ETH1
+ if (!eth_getenv_enetaddr("eth1addr", enetaddr)) {
+ board_get_enetaddr(1, enetaddr);
+ eth_putenv_enetaddr("eth1addr", enetaddr);
+ }
+#endif
+
+#ifdef CONFIG_HAS_ETH2
+ if (!eth_getenv_enetaddr("eth2addr", enetaddr)) {
+ board_get_enetaddr(2, enetaddr);
+ eth_putenv_enetaddr("eth2addr", enetaddr);
+ }
+#endif
+
+#ifdef CONFIG_HAS_ETH3
+ if (!eth_getenv_enetaddr("eth3addr", enetaddr)) {
+ board_get_enetaddr(3, enetaddr);
+ eth_putenv_enetaddr("eth3addr", enetaddr);
+ }
+#endif
+
return (0);
}
diff --git a/board/sandburst/metrobox/u-boot.lds b/board/sandburst/metrobox/u-boot.lds
index 54e18e0..f1bc4a0 100644
--- a/board/sandburst/metrobox/u-boot.lds
+++ b/board/sandburst/metrobox/u-boot.lds
@@ -91,10 +91,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/sbc2410x/u-boot.lds b/board/sbc2410x/u-boot.lds
index d0666ac..3eae0e2 100644
--- a/board/sbc2410x/u-boot.lds
+++ b/board/sbc2410x/u-boot.lds
@@ -37,7 +37,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/sbc405/u-boot.lds b/board/sbc405/u-boot.lds
index d6f34c9..d9410fa 100644
--- a/board/sbc405/u-boot.lds
+++ b/board/sbc405/u-boot.lds
@@ -83,10 +83,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/sbc8548/u-boot.lds b/board/sbc8548/u-boot.lds
index 70d11f2..a54a001 100644
--- a/board/sbc8548/u-boot.lds
+++ b/board/sbc8548/u-boot.lds
@@ -80,10 +80,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/sbc8560/u-boot.lds b/board/sbc8560/u-boot.lds
index 759ee82..8c12ba4 100644
--- a/board/sbc8560/u-boot.lds
+++ b/board/sbc8560/u-boot.lds
@@ -86,10 +86,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/sbc8641d/u-boot.lds b/board/sbc8641d/u-boot.lds
index adfa816..f156d4f 100644
--- a/board/sbc8641d/u-boot.lds
+++ b/board/sbc8641d/u-boot.lds
@@ -68,10 +68,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/sc3/u-boot.lds b/board/sc3/u-boot.lds
index d729f2e..75174e1 100644
--- a/board/sc3/u-boot.lds
+++ b/board/sc3/u-boot.lds
@@ -84,10 +84,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/sc520_cdp/sc520_cdp.c b/board/sc520_cdp/sc520_cdp.c
index 779f957..830ec37 100644
--- a/board/sc520_cdp/sc520_cdp.c
+++ b/board/sc520_cdp/sc520_cdp.c
@@ -27,7 +27,7 @@
#include <asm/io.h>
#include <asm/pci.h>
#include <asm/ic/sc520.h>
-#include <asm/ic/ali512x.h>
+#include <ali512x.h>
#include <spi.h>
#include <netdev.h>
@@ -575,10 +575,10 @@ int spi_eeprom_write(int x, int offset, uchar *buffer, int len)
void spi_init_f(void)
{
-#ifdef CONFIG_SC520_CDP_USE_SPI
+#ifdef CONFIG_SYS_SC520_CDP_USE_SPI
spi_eeprom_probe(1);
#endif
-#ifdef CONFIG_SC520_CDP_USE_MW
+#ifdef CONFIG_SYS_SC520_CDP_USE_MW
mw_eeprom_probe(2);
#endif
}
@@ -595,13 +595,13 @@ ssize_t spi_read(uchar *addr, int alen, uchar *buffer, int len)
offset |= addr[i];
}
-#ifdef CONFIG_SC520_CDP_USE_SPI
+#ifdef CONFIG_SYS_SC520_CDP_USE_SPI
res = spi_eeprom_read(1, offset, buffer, len);
#endif
-#ifdef CONFIG_SC520_CDP_USE_MW
+#ifdef CONFIG_SYS_SC520_CDP_USE_MW
res = mw_eeprom_read(2, offset, buffer, len);
#endif
-#if !defined(CONFIG_SC520_CDP_USE_SPI) && !defined(CONFIG_SC520_CDP_USE_MW)
+#if !defined(CONFIG_SYS_SC520_CDP_USE_SPI) && !defined(CONFIG_SYS_SC520_CDP_USE_MW)
res = 0;
#endif
return res;
@@ -619,13 +619,13 @@ ssize_t spi_write(uchar *addr, int alen, uchar *buffer, int len)
offset |= addr[i];
}
-#ifdef CONFIG_SC520_CDP_USE_SPI
+#ifdef CONFIG_SYS_SC520_CDP_USE_SPI
res = spi_eeprom_write(1, offset, buffer, len);
#endif
-#ifdef CONFIG_SC520_CDP_USE_MW
+#ifdef CONFIG_SYS_SC520_CDP_USE_MW
res = mw_eeprom_write(2, offset, buffer, len);
#endif
-#if !defined(CONFIG_SC520_CDP_USE_SPI) && !defined(CONFIG_SC520_CDP_USE_MW)
+#if !defined(CONFIG_SYS_SC520_CDP_USE_SPI) && !defined(CONFIG_SYS_SC520_CDP_USE_MW)
res = 0;
#endif
return res;
diff --git a/board/sc520_cdp/u-boot.lds b/board/sc520_cdp/u-boot.lds
index 0f5011a..df437c7 100644
--- a/board/sc520_cdp/u-boot.lds
+++ b/board/sc520_cdp/u-boot.lds
@@ -31,7 +31,7 @@ SECTIONS
.text : { *(.text); }
. = ALIGN(4);
- .rodata : { *(.rodata) *(.rodata.str1.1) *(.rodata.str1.32) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = 0x400000; /* Ram data segment to use */
_i386boot_romdata_dest = ABSOLUTE(.);
diff --git a/board/sc520_spunk/u-boot.lds b/board/sc520_spunk/u-boot.lds
index d2436bc..efb570b 100644
--- a/board/sc520_spunk/u-boot.lds
+++ b/board/sc520_spunk/u-boot.lds
@@ -32,7 +32,7 @@ SECTIONS
.text : { *(.text); }
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = 0x400000; /* Ram data segment to use */
_i386boot_romdata_dest = ABSOLUTE(.);
diff --git a/board/scb9328/u-boot.lds b/board/scb9328/u-boot.lds
index c96e58a..d912d93 100644
--- a/board/scb9328/u-boot.lds
+++ b/board/scb9328/u-boot.lds
@@ -37,7 +37,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/shannon/u-boot.lds b/board/shannon/u-boot.lds
index fce2533..13b7bb7 100644
--- a/board/shannon/u-boot.lds
+++ b/board/shannon/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/siemens/CCM/u-boot.lds b/board/siemens/CCM/u-boot.lds
index ef9a251..61650a8 100644
--- a/board/siemens/CCM/u-boot.lds
+++ b/board/siemens/CCM/u-boot.lds
@@ -73,10 +73,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/siemens/IAD210/IAD210.c b/board/siemens/IAD210/IAD210.c
index e21bb24..67e5c8f 100644
--- a/board/siemens/IAD210/IAD210.c
+++ b/board/siemens/IAD210/IAD210.c
@@ -258,7 +258,7 @@ int board_early_init_f (void)
return 0;
}
-void board_get_enetaddr (uchar * addr)
+static void board_get_enetaddr(uchar *addr)
{
int i;
volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
@@ -284,3 +284,15 @@ void board_get_enetaddr (uchar * addr)
cpm->cp_rccr = rccrtmp;
}
+
+int misc_init_r(void)
+{
+ uchar enetaddr[6];
+
+ if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
+ board_get_enetaddr(enetaddr);
+ eth_putenv_enetaddr("ethaddr", enetaddr);
+ }
+
+ return 0;
+}
diff --git a/board/siemens/IAD210/u-boot.lds b/board/siemens/IAD210/u-boot.lds
index 47677c6..12a53ba 100644
--- a/board/siemens/IAD210/u-boot.lds
+++ b/board/siemens/IAD210/u-boot.lds
@@ -71,10 +71,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/siemens/SMN42/u-boot.lds b/board/siemens/SMN42/u-boot.lds
index 49d18f7..cb5a3ba 100644
--- a/board/siemens/SMN42/u-boot.lds
+++ b/board/siemens/SMN42/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/siemens/pcu_e/u-boot.lds b/board/siemens/pcu_e/u-boot.lds
index 319cc7b..9e46f9d 100644
--- a/board/siemens/pcu_e/u-boot.lds
+++ b/board/siemens/pcu_e/u-boot.lds
@@ -62,10 +62,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/sixnet/sixnet.c b/board/sixnet/sixnet.c
index 3ed581e..4fcd84b 100644
--- a/board/sixnet/sixnet.c
+++ b/board/sixnet/sixnet.c
@@ -264,6 +264,7 @@ int misc_init_r (void)
char* e;
int reg;
bd_t *bd = gd->bd;
+ uchar enetaddr[6];
memctl->memc_or2 = NVRAM_OR_PRELIM;
memctl->memc_br2 = NVRAM_BR_VALUE;
@@ -315,13 +316,9 @@ int misc_init_r (void)
* is present it gets a unique address, otherwise it
* shares the FEC address.
*/
- s = getenv("eth1addr");
- if (s == NULL)
- s = getenv("ethaddr");
- for (reg=0; reg<6; ++reg) {
- bd->bi_enet1addr[reg] = s ? simple_strtoul(s, &e, 16) : 0;
- if (s)
- s = (*e) ? e+1 : e;
+ if (!eth_getenv_enetaddr("eth1addr", enetaddr)) {
+ eth_getenv_enetaddr("ethaddr", enetaddr);
+ eth_setenv_enetaddr("eth1addr", enetaddr);
}
return (0);
diff --git a/board/sixnet/u-boot.lds b/board/sixnet/u-boot.lds
index efa4244..bde981b 100644
--- a/board/sixnet/u-boot.lds
+++ b/board/sixnet/u-boot.lds
@@ -62,10 +62,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/snmc/qs850/u-boot.lds b/board/snmc/qs850/u-boot.lds
index 6fa9b81..7de0de8 100644
--- a/board/snmc/qs850/u-boot.lds
+++ b/board/snmc/qs850/u-boot.lds
@@ -76,10 +76,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/snmc/qs860t/u-boot.lds b/board/snmc/qs860t/u-boot.lds
index 6fa9b81..7de0de8 100644
--- a/board/snmc/qs860t/u-boot.lds
+++ b/board/snmc/qs860t/u-boot.lds
@@ -76,10 +76,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/socrates/u-boot.lds b/board/socrates/u-boot.lds
index 499f531..9241b5c 100644
--- a/board/socrates/u-boot.lds
+++ b/board/socrates/u-boot.lds
@@ -84,10 +84,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/spc1920/u-boot.lds b/board/spc1920/u-boot.lds
index 5af36c9..4e221bc 100644
--- a/board/spc1920/u-boot.lds
+++ b/board/spc1920/u-boot.lds
@@ -76,10 +76,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/spd8xx/u-boot.lds b/board/spd8xx/u-boot.lds
index 7d94421..a06d8c6 100644
--- a/board/spd8xx/u-boot.lds
+++ b/board/spd8xx/u-boot.lds
@@ -62,10 +62,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/ssv/adnpesc1/u-boot.lds b/board/ssv/adnpesc1/u-boot.lds
index be77952..98ee8f8 100644
--- a/board/ssv/adnpesc1/u-boot.lds
+++ b/board/ssv/adnpesc1/u-boot.lds
@@ -38,7 +38,7 @@ SECTIONS
. = ALIGN(4);
.rodata :
{
- *(.rodata)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
__rodata_end = .;
diff --git a/board/st/nmdk8815/u-boot.lds b/board/st/nmdk8815/u-boot.lds
index 6d6481b..c2adbab 100644
--- a/board/st/nmdk8815/u-boot.lds
+++ b/board/st/nmdk8815/u-boot.lds
@@ -34,7 +34,7 @@ SECTIONS
*(.text)
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
diff --git a/board/stxgp3/u-boot.lds b/board/stxgp3/u-boot.lds
index cdcb39a..182e940 100644
--- a/board/stxgp3/u-boot.lds
+++ b/board/stxgp3/u-boot.lds
@@ -88,10 +88,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/stxssa/u-boot.lds b/board/stxssa/u-boot.lds
index 6ee8d60..750ddb3 100644
--- a/board/stxssa/u-boot.lds
+++ b/board/stxssa/u-boot.lds
@@ -88,10 +88,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/stxxtc/u-boot.lds b/board/stxxtc/u-boot.lds
index 4966f4d..14201ac 100644
--- a/board/stxxtc/u-boot.lds
+++ b/board/stxxtc/u-boot.lds
@@ -73,10 +73,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/svm_sc8xx/u-boot.lds b/board/svm_sc8xx/u-boot.lds
index ceab4d2..11a819a 100644
--- a/board/svm_sc8xx/u-boot.lds
+++ b/board/svm_sc8xx/u-boot.lds
@@ -76,10 +76,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/sx1/u-boot.lds b/board/sx1/u-boot.lds
index 9a9dd21..af0b4d0 100644
--- a/board/sx1/u-boot.lds
+++ b/board/sx1/u-boot.lds
@@ -37,7 +37,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/tb0229/u-boot.lds b/board/tb0229/u-boot.lds
index 086d74d..56d7c25 100644
--- a/board/tb0229/u-boot.lds
+++ b/board/tb0229/u-boot.lds
@@ -38,7 +38,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/tqc/tqm85xx/u-boot.lds b/board/tqc/tqm85xx/u-boot.lds
index b1637a5..91c8952 100644
--- a/board/tqc/tqm85xx/u-boot.lds
+++ b/board/tqc/tqm85xx/u-boot.lds
@@ -81,10 +81,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/tqc/tqm8xx/tqm8xx.c b/board/tqc/tqm8xx/tqm8xx.c
index e065d69..f92c598 100644
--- a/board/tqc/tqm8xx/tqm8xx.c
+++ b/board/tqc/tqm8xx/tqm8xx.c
@@ -449,11 +449,14 @@ int board_early_init_r (void)
#ifdef CONFIG_MISC_INIT_R
+extern void load_sernum_ethaddr(void);
int misc_init_r (void)
{
volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
volatile memctl8xx_t *memctl = &immap->im_memctl;
+ load_sernum_ethaddr();
+
#ifdef CONFIG_SYS_OR_TIMING_FLASH_AT_50MHZ
int scy, trlx, flash_or_timing, clk_diff;
diff --git a/board/tqc/tqm8xx/u-boot.lds b/board/tqc/tqm8xx/u-boot.lds
index 5c9b26c..19c1541 100644
--- a/board/tqc/tqm8xx/u-boot.lds
+++ b/board/tqc/tqm8xx/u-boot.lds
@@ -75,10 +75,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/trab/u-boot.lds b/board/trab/u-boot.lds
index bd13d13..912a2bb 100644
--- a/board/trab/u-boot.lds
+++ b/board/trab/u-boot.lds
@@ -45,7 +45,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/trizepsiv/u-boot.lds b/board/trizepsiv/u-boot.lds
index 7cf9fdf..a077bc5 100644
--- a/board/trizepsiv/u-boot.lds
+++ b/board/trizepsiv/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/uc100/u-boot.lds b/board/uc100/u-boot.lds
index 66a57e6..1450d37 100644
--- a/board/uc100/u-boot.lds
+++ b/board/uc100/u-boot.lds
@@ -75,10 +75,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/v37/u-boot.lds b/board/v37/u-boot.lds
index bf78a32..d24289c 100644
--- a/board/v37/u-boot.lds
+++ b/board/v37/u-boot.lds
@@ -78,10 +78,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/v38b/v38b.c b/board/v38b/v38b.c
index d774295..9e7c1d7 100644
--- a/board/v38b/v38b.c
+++ b/board/v38b/v38b.c
@@ -223,6 +223,18 @@ int board_early_init_r(void)
return 0;
}
+extern void board_get_enetaddr(uchar *enetaddr);
+int misc_init_r(void)
+{
+ uchar enetaddr[6];
+
+ if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
+ board_get_enetaddr(enetaddr);
+ eth_putenv_enetaddr("ethaddr", enetaddr);
+ }
+
+ return 0;
+}
#if defined(CONFIG_CMD_IDE) && defined(CONFIG_IDE_RESET)
void init_ide_reset(void)
diff --git a/board/voiceblue/eeprom.lds b/board/voiceblue/eeprom.lds
index f3be320..132476d 100644
--- a/board/voiceblue/eeprom.lds
+++ b/board/voiceblue/eeprom.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/voiceblue/u-boot.lds b/board/voiceblue/u-boot.lds
index 8bf1990..97fcef3 100644
--- a/board/voiceblue/u-boot.lds
+++ b/board/voiceblue/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/w7o/u-boot.lds b/board/w7o/u-boot.lds
index 80e960b..191a179 100644
--- a/board/w7o/u-boot.lds
+++ b/board/w7o/u-boot.lds
@@ -67,10 +67,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/wepep250/u-boot.lds b/board/wepep250/u-boot.lds
index 7cf9fdf..a077bc5 100644
--- a/board/wepep250/u-boot.lds
+++ b/board/wepep250/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/westel/amx860/u-boot.lds b/board/westel/amx860/u-boot.lds
index ef9a251..61650a8 100644
--- a/board/westel/amx860/u-boot.lds
+++ b/board/westel/amx860/u-boot.lds
@@ -73,10 +73,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/xaeniax/u-boot.lds b/board/xaeniax/u-boot.lds
index 7cf9fdf..a077bc5 100644
--- a/board/xaeniax/u-boot.lds
+++ b/board/xaeniax/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/xes/xpedite5200/u-boot.lds b/board/xes/xpedite5200/u-boot.lds
index bd952d2..af4f016 100644
--- a/board/xes/xpedite5200/u-boot.lds
+++ b/board/xes/xpedite5200/u-boot.lds
@@ -65,10 +65,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
} :text
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/xes/xpedite5370/u-boot.lds b/board/xes/xpedite5370/u-boot.lds
index cb39912..f117d9b 100644
--- a/board/xes/xpedite5370/u-boot.lds
+++ b/board/xes/xpedite5370/u-boot.lds
@@ -65,10 +65,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
} :text
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/xilinx/microblaze-generic/u-boot.lds b/board/xilinx/microblaze-generic/u-boot.lds
index b38f648..5a08680 100644
--- a/board/xilinx/microblaze-generic/u-boot.lds
+++ b/board/xilinx/microblaze-generic/u-boot.lds
@@ -38,7 +38,7 @@ SECTIONS
.rodata ALIGN(0x4):
{
__rodata_start = .;
- *(.rodata)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
__rodata_end = .;
}
diff --git a/board/xilinx/ml300/u-boot.lds b/board/xilinx/ml300/u-boot.lds
index 913ff6e..fa60e6b 100644
--- a/board/xilinx/ml300/u-boot.lds
+++ b/board/xilinx/ml300/u-boot.lds
@@ -81,10 +81,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/xilinx/ppc405-generic/u-boot-ram.lds b/board/xilinx/ppc405-generic/u-boot-ram.lds
index 6bbd3bd..908d84b 100644
--- a/board/xilinx/ppc405-generic/u-boot-ram.lds
+++ b/board/xilinx/ppc405-generic/u-boot-ram.lds
@@ -64,10 +64,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/xilinx/ppc405-generic/u-boot-rom.lds b/board/xilinx/ppc405-generic/u-boot-rom.lds
index d094006..592976a 100644
--- a/board/xilinx/ppc405-generic/u-boot-rom.lds
+++ b/board/xilinx/ppc405-generic/u-boot-rom.lds
@@ -74,10 +74,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/xilinx/ppc440-generic/u-boot-ram.lds b/board/xilinx/ppc440-generic/u-boot-ram.lds
index d65f3de..3ab9a31 100644
--- a/board/xilinx/ppc440-generic/u-boot-ram.lds
+++ b/board/xilinx/ppc440-generic/u-boot-ram.lds
@@ -64,10 +64,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/xilinx/ppc440-generic/u-boot-rom.lds b/board/xilinx/ppc440-generic/u-boot-rom.lds
index 8b468ee..7420280 100644
--- a/board/xilinx/ppc440-generic/u-boot-rom.lds
+++ b/board/xilinx/ppc440-generic/u-boot-rom.lds
@@ -74,10 +74,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/xilinx/xilinx_enet/emac_adapter.c b/board/xilinx/xilinx_enet/emac_adapter.c
index 0b100d2..35bcc4d 100644
--- a/board/xilinx/xilinx_enet/emac_adapter.c
+++ b/board/xilinx/xilinx_enet/emac_adapter.c
@@ -74,6 +74,7 @@ eth_init(bd_t * bis)
{
u32 Options;
XStatus Result;
+ uchar enetaddr[6];
#ifdef DEBUG
printf("EMAC Initialization Started\n\r");
@@ -87,11 +88,14 @@ eth_init(bd_t * bis)
/* make sure the Emac is stopped before it is started */
(void) XEmac_Stop(&Emac);
+ if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
#ifdef CONFIG_ENV_IS_NOWHERE
- memcpy(bis->bi_enetaddr, EMACAddr, 6);
+ memcpy(enetaddr, EMACAddr, 6);
+ eth_setenv_enetaddr("ethaddr", enetaddr);
#endif
+ }
- Result = XEmac_SetMacAddress(&Emac, bis->bi_enetaddr);
+ Result = XEmac_SetMacAddress(&Emac, enetaddr);
if (Result != XST_SUCCESS) {
return 0;
}
diff --git a/board/xm250/u-boot.lds b/board/xm250/u-boot.lds
index 1e88820..8af5001 100644
--- a/board/xm250/u-boot.lds
+++ b/board/xm250/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/xpedite1k/u-boot.lds b/board/xpedite1k/u-boot.lds
index 13c52b9..c8f9646 100644
--- a/board/xpedite1k/u-boot.lds
+++ b/board/xpedite1k/u-boot.lds
@@ -89,10 +89,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/xpedite1k/u-boot.lds.debug b/board/xpedite1k/u-boot.lds.debug
index 116c2ba..5824cd9 100644
--- a/board/xpedite1k/u-boot.lds.debug
+++ b/board/xpedite1k/u-boot.lds.debug
@@ -78,10 +78,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/xpedite1k/xpedite1k.c b/board/xpedite1k/xpedite1k.c
index 58bcfaf..cd1a368 100644
--- a/board/xpedite1k/xpedite1k.c
+++ b/board/xpedite1k/xpedite1k.c
@@ -335,29 +335,58 @@ ulong post_word_load (void)
* board_get_enetaddr -- Read the MAC Addresses in the I2C EEPROM
*-----------------------------------------------------------------------------
*/
-static int enetaddr_num = 0;
-void board_get_enetaddr (uchar * enet)
+static int read_i2c;
+static void board_get_enetaddr(uchar *enet)
{
int i;
unsigned char buff[0x100], *cp;
+ if (read_i2c)
+ return;
+
/* Initialize I2C */
i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
/* Read 256 bytes in EEPROM */
i2c_read (0x50, 0, 1, buff, 0x100);
- if (enetaddr_num == 0) {
- cp = &buff[0xF4];
- enetaddr_num = 1;
- }
- else
- cp = &buff[0xFA];
-
+ cp = &buff[0xF4];
for (i = 0; i < 6; i++,cp++)
enet[i] = *cp;
- printf ("MAC address = %02x:%02x:%02x:%02x:%02x:%02x\n",
- enet[0], enet[1], enet[2], enet[3], enet[4], enet[5]);
+ printf("MAC address = %pM\n", enet);
+ read_i2c = 1;
+}
+
+int misc_init_r(void)
+{
+ uchar enetaddr[6], i2c_enetaddr[6];
+
+ if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
+ board_get_enetaddr(i2c_enetaddr);
+ eth_putenv_enetaddr("ethaddr", i2c_enetaddr);
+ }
+
+#ifdef CONFIG_HAS_ETH1
+ if (!eth_getenv_enetaddr("eth1addr", enetaddr)) {
+ board_get_enetaddr(i2c_enetaddr);
+ eth_putenv_enetaddr("eth1addr", i2c_enetaddr);
+ }
+#endif
+
+#ifdef CONFIG_HAS_ETH2
+ if (!eth_getenv_enetaddr("eth2addr", enetaddr)) {
+ board_get_enetaddr(i2c_enetaddr);
+ eth_putenv_enetaddr("eth2addr", i2c_enetaddr);
+ }
+#endif
+#ifdef CONFIG_HAS_ETH3
+ if (!eth_getenv_enetaddr("eth3addr", enetaddr)) {
+ board_get_enetaddr(i2c_enetaddr);
+ eth_putenv_enetaddr("eth3addr", i2c_enetaddr);
+ }
+#endif
+
+ return 0;
}
diff --git a/board/xsengine/u-boot.lds b/board/xsengine/u-boot.lds
index 1e88820..8af5001 100644
--- a/board/xsengine/u-boot.lds
+++ b/board/xsengine/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/board/zeus/u-boot.lds b/board/zeus/u-boot.lds
index 877573e..f86570d 100644
--- a/board/zeus/u-boot.lds
+++ b/board/zeus/u-boot.lds
@@ -67,9 +67,7 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/board/zylonite/u-boot.lds b/board/zylonite/u-boot.lds
index 7cf9fdf..a077bc5 100644
--- a/board/zylonite/u-boot.lds
+++ b/board/zylonite/u-boot.lds
@@ -36,7 +36,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/common/Makefile b/common/Makefile
index f13cd11..23171ca 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -110,6 +110,7 @@ COBJS-$(CONFIG_CMD_MII) += cmd_mii.o
COBJS-$(CONFIG_CMD_MISC) += cmd_misc.o
COBJS-$(CONFIG_CMD_MMC) += cmd_mmc.o
COBJS-$(CONFIG_MP) += cmd_mp.o
+COBJS-$(CONFIG_CMD_MTDPARTS) += cmd_mtdparts.o
COBJS-y += cmd_nand.o
COBJS-$(CONFIG_CMD_NET) += cmd_net.o
COBJS-$(CONFIG_CMD_ONENAND) += cmd_onenand.o
@@ -129,6 +130,7 @@ COBJS-$(CONFIG_CMD_SPI) += cmd_spi.o
COBJS-$(CONFIG_CMD_STRINGS) += cmd_strings.o
COBJS-$(CONFIG_CMD_TERMINAL) += cmd_terminal.o
COBJS-$(CONFIG_CMD_UBI) += cmd_ubi.o
+COBJS-$(CONFIG_CMD_UBIFS) += cmd_ubifs.o
COBJS-$(CONFIG_CMD_UNIVERSE) += cmd_universe.o
ifdef CONFIG_CMD_USB
COBJS-y += cmd_usb.o
diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c
index b2d6f84..700314b 100644
--- a/common/cmd_bdinfo.c
+++ b/common/cmd_bdinfo.c
@@ -26,12 +26,13 @@
*/
#include <common.h>
#include <command.h>
-#include <net.h> /* for print_IPaddr */
DECLARE_GLOBAL_DATA_PTR;
static void print_num(const char *, ulong);
+static void print_eth(int idx);
+
#ifndef CONFIG_ARM /* PowerPC and other */
static void print_lnum(const char *, u64);
@@ -40,7 +41,6 @@ static void print_str(const char *, const char *);
int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
- int i;
bd_t *bd = gd->bd;
char buf[32];
@@ -91,51 +91,28 @@ int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
print_str ("pevfreq", strmhz(buf, bd->bi_pevfreq));
#endif
- puts ("ethaddr =");
- for (i=0; i<6; ++i) {
- printf ("%c%02X", i ? ':' : ' ', bd->bi_enetaddr[i]);
- }
-
+ print_eth(0);
#if defined(CONFIG_HAS_ETH1)
- puts ("\neth1addr =");
- for (i=0; i<6; ++i) {
- printf ("%c%02X", i ? ':' : ' ', bd->bi_enet1addr[i]);
- }
+ print_eth(1);
#endif
-
#if defined(CONFIG_HAS_ETH2)
- puts ("\neth2addr =");
- for (i=0; i<6; ++i) {
- printf ("%c%02X", i ? ':' : ' ', bd->bi_enet2addr[i]);
- }
+ print_eth(2);
#endif
-
#if defined(CONFIG_HAS_ETH3)
- puts ("\neth3addr =");
- for (i=0; i<6; ++i) {
- printf ("%c%02X", i ? ':' : ' ', bd->bi_enet3addr[i]);
- }
+ print_eth(3);
#endif
-
#if defined(CONFIG_HAS_ETH4)
- puts ("\neth4addr =");
- for (i=0; i<6; ++i) {
- printf ("%c%02X", i ? ':' : ' ', bd->bi_enet4addr[i]);
- }
+ print_eth(4);
#endif
-
#if defined(CONFIG_HAS_ETH5)
- puts ("\neth5addr =");
- for (i=0; i<6; ++i) {
- printf ("%c%02X", i ? ':' : ' ', bd->bi_enet5addr[i]);
- }
+ print_eth(5);
#endif
#ifdef CONFIG_HERMES
print_str ("ethspeed", strmhz(buf, bd->bi_ethspeed));
#endif
- puts ("\nIP addr = "); print_IPaddr (bd->bi_ip_addr);
- printf ("\nbaudrate = %6ld bps\n", bd->bi_baudrate );
+ printf ("IP addr = %pI4\n", &bd->bi_ip_addr);
+ printf ("baudrate = %6ld bps\n", bd->bi_baudrate );
return 0;
}
@@ -143,7 +120,6 @@ int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
- int i;
bd_t *bd = gd->bd;
print_num ("memstart", (ulong)bd->bi_memstart);
@@ -152,13 +128,9 @@ int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
print_num ("flashsize", (ulong)bd->bi_flashsize);
print_num ("flashoffset", (ulong)bd->bi_flashoffset);
- puts ("ethaddr =");
- for (i=0; i<6; ++i) {
- printf ("%c%02X", i ? ':' : ' ', bd->bi_enetaddr[i]);
- }
- puts ("\nip_addr = ");
- print_IPaddr (bd->bi_ip_addr);
- printf ("\nbaudrate = %ld bps\n", bd->bi_baudrate);
+ print_eth(0);
+ printf ("ip_addr = %pI4\n", &bd->bi_ip_addr);
+ printf ("baudrate = %ld bps\n", bd->bi_baudrate);
return 0;
}
@@ -167,9 +139,6 @@ int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
-#if defined(CONFIG_CMD_NET)
- int i;
-#endif
bd_t *bd = gd->bd;
print_num ("mem start", (ulong)bd->bi_memstart);
@@ -184,15 +153,11 @@ int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
#endif
#if defined(CONFIG_CMD_NET)
- puts ("ethaddr =");
- for (i=0; i<6; ++i) {
- printf ("%c%02X", i ? ':' : ' ', bd->bi_enetaddr[i]);
- }
- puts ("\nip_addr = ");
- print_IPaddr (bd->bi_ip_addr);
+ print_eth(0);
+ printf ("ip_addr = %pI4\n", &bd->bi_ip_addr);
#endif
- printf ("\nbaudrate = %ld bps\n", bd->bi_baudrate);
+ printf ("baudrate = %ld bps\n", bd->bi_baudrate);
return 0;
}
@@ -200,7 +165,6 @@ int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
- int i;
bd_t *bd = gd->bd;
print_num ("mem start ", (ulong)bd->bi_memstart);
print_lnum ("mem size ", (u64)bd->bi_memsize);
@@ -212,14 +176,10 @@ int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
print_num ("sram size ", (ulong)bd->bi_sramsize);
#endif
#if defined(CONFIG_CMD_NET)
- puts ("ethaddr =");
- for (i=0; i<6; ++i) {
- printf ("%c%02X", i ? ':' : ' ', bd->bi_enetaddr[i]);
- }
- puts ("\nip_addr = ");
- print_IPaddr (bd->bi_ip_addr);
+ print_eth(0);
+ printf ("ip_addr = %pI4\n", &bd->bi_ip_addr);
#endif
- printf ("\nbaudrate = %ld bps\n", (ulong)bd->bi_baudrate);
+ printf ("baudrate = %ld bps\n", (ulong)bd->bi_baudrate);
return 0;
}
@@ -227,9 +187,6 @@ int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
int do_bdinfo(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
bd_t *bd = gd->bd;
-#if defined(CONFIG_CMD_NET)
- int i;
-#endif
#ifdef DEBUG
print_num("bd address ", (ulong) bd);
@@ -251,14 +208,10 @@ int do_bdinfo(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
CONFIG_SYS_GBL_DATA_SIZE);
#if defined(CONFIG_CMD_NET)
- puts("ethaddr =");
- for (i = 0; i < 6; ++i) {
- printf("%c%02X", i ? ':' : ' ', bd->bi_enetaddr[i]);
- }
- puts("\nIP addr = ");
- print_IPaddr(bd->bi_ip_addr);
+ print_eth(0);
+ printf("ip_addr = %pI4\n", &bd->bi_ip_addr);
#endif
- printf("\nbaudrate = %6ld bps\n", bd->bi_baudrate);
+ printf("baudrate = %6ld bps\n", bd->bi_baudrate);
return 0;
}
@@ -267,7 +220,6 @@ static void print_str(const char *, const char *);
int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
- int i;
bd_t *bd = gd->bd;
char buf[32];
@@ -294,36 +246,20 @@ int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
print_str ("vcofreq", strmhz(buf, bd->bi_vcofreq));
#endif
#if defined(CONFIG_CMD_NET)
- puts ("ethaddr =");
- for (i=0; i<6; ++i) {
- printf ("%c%02X", i ? ':' : ' ', bd->bi_enetaddr[i]);
- }
-
+ print_eth(0);
#if defined(CONFIG_HAS_ETH1)
- puts ("\neth1addr =");
- for (i=0; i<6; ++i) {
- printf ("%c%02X", i ? ':' : ' ', bd->bi_enet1addr[i]);
- }
+ print_eth(1);
#endif
-
#if defined(CONFIG_HAS_ETH2)
- puts ("\neth2addr =");
- for (i=0; i<6; ++i) {
- printf ("%c%02X", i ? ':' : ' ', bd->bi_enet2addr[i]);
- }
+ print_eth(2);
#endif
-
#if defined(CONFIG_HAS_ETH3)
- puts ("\neth3addr =");
- for (i=0; i<6; ++i) {
- printf ("%c%02X", i ? ':' : ' ', bd->bi_enet3addr[i]);
- }
+ print_eth(3);
#endif
- puts ("\nip_addr = ");
- print_IPaddr (bd->bi_ip_addr);
+ printf ("ip_addr = %pI4\n", &bd->bi_ip_addr);
#endif
- printf ("\nbaudrate = %ld bps\n", bd->bi_baudrate);
+ printf ("baudrate = %ld bps\n", bd->bi_baudrate);
return 0;
}
@@ -333,7 +269,6 @@ static void print_str(const char *, const char *);
int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
- int i;
bd_t *bd = gd->bd;
char buf[32];
@@ -351,12 +286,9 @@ int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
print_num("flashsize", (ulong)bd->bi_flashsize);
print_num("flashoffset", (ulong)bd->bi_flashoffset);
- puts("ethaddr =");
- for (i = 0; i < 6; ++i)
- printf("%c%02X", i ? ':' : ' ', bd->bi_enetaddr[i]);
- puts("\nip_addr = ");
- print_IPaddr(bd->bi_ip_addr);
- printf("\nbaudrate = %d bps\n", bd->bi_baudrate);
+ print_eth(0);
+ printf("ip_addr = %pI4\n", &bd->bi_ip_addr);
+ printf("baudrate = %d bps\n", bd->bi_baudrate);
return 0;
}
@@ -365,7 +297,6 @@ int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
- int i;
bd_t *bd = gd->bd;
print_num ("boot_params", (ulong)bd->bi_boot_params);
@@ -375,13 +306,9 @@ int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
print_num ("flashsize", (ulong)bd->bi_flashsize);
print_num ("flashoffset", (ulong)bd->bi_flashoffset);
- puts ("ethaddr =");
- for (i=0; i<6; ++i) {
- printf ("%c%02X", i ? ':' : ' ', bd->bi_enetaddr[i]);
- }
- puts ("\nip_addr = ");
- print_IPaddr (bd->bi_ip_addr);
- printf ("\nbaudrate = %d bps\n", bd->bi_baudrate);
+ print_eth(0);
+ printf ("ip_addr = %pI4\n", &bd->bi_ip_addr);
+ printf ("baudrate = %d bps\n", bd->bi_baudrate);
return 0;
}
@@ -405,16 +332,10 @@ int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
}
#if defined(CONFIG_CMD_NET)
- puts ("ethaddr =");
- for (i=0; i<6; ++i) {
- printf ("%c%02X", i ? ':' : ' ', bd->bi_enetaddr[i]);
- }
- puts ( "\n"
- "ip_addr = ");
- print_IPaddr (bd->bi_ip_addr);
+ print_eth(0);
+ printf ("ip_addr = %pI4\n", &bd->bi_ip_addr);
#endif
- printf ("\n"
- "baudrate = %d bps\n", bd->bi_baudrate);
+ printf ("baudrate = %d bps\n", bd->bi_baudrate);
return 0;
}
@@ -426,6 +347,19 @@ static void print_num(const char *name, ulong value)
printf ("%-12s= 0x%08lX\n", name, value);
}
+static void print_eth(int idx)
+{
+ char name[10], *val;
+ if (idx)
+ sprintf(name, "eth%iaddr", idx);
+ else
+ strcpy(name, "ethaddr");
+ val = getenv(name);
+ if (!val)
+ val = "(not set)";
+ printf("%-12s= %s\n", name, val);
+}
+
#ifndef CONFIG_ARM
static void print_lnum(const char *name, u64 value)
{
diff --git a/common/cmd_elf.c b/common/cmd_elf.c
index 19e1249..4a3fff1 100644
--- a/common/cmd_elf.c
+++ b/common/cmd_elf.c
@@ -131,10 +131,12 @@ int do_bootvx (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
#if defined(CONFIG_WALNUT)
tmp = (char *) CONFIG_SYS_NVRAM_BASE_ADDR + 0x500;
- memcpy ((char *) tmp, (char *) &gd->bd->bi_enetaddr[3], 3);
+ eth_getenv_enetaddr("ethaddr", build_buf);
+ memcpy(tmp, &build_buf[3], 3);
#elif defined(CONFIG_SYS_VXWORKS_MAC_PTR)
tmp = (char *) CONFIG_SYS_VXWORKS_MAC_PTR;
- memcpy ((char *) tmp, (char *) &gd->bd->bi_enetaddr[0], 6);
+ eth_getenv_enetaddr("ethaddr", build_buf);
+ memcpy(tmp, build_buf, 6);
#else
puts ("## Ethernet MAC address not copied to NV RAM\n");
#endif
diff --git a/common/cmd_flash.c b/common/cmd_flash.c
index 510654e..f1f3517 100644
--- a/common/cmd_flash.c
+++ b/common/cmd_flash.c
@@ -31,12 +31,12 @@
#include <dataflash.h>
#endif
-#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
#include <jffs2/jffs2.h>
/* parition handling routines */
int mtdparts_init(void);
-int id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num);
+int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num);
int find_dev_and_part(const char *id, struct mtd_device **dev,
u8 *part_num, struct part_info **part);
#endif
@@ -325,7 +325,7 @@ int do_flerase (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
flash_info_t *info;
ulong bank, addr_first, addr_last;
int n, sect_first, sect_last;
-#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
struct mtd_device *dev;
struct part_info *part;
u8 dev_type, dev_num, pnum;
@@ -357,9 +357,9 @@ int do_flerase (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
return rcode;
}
-#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
/* erase <part-id> - erase partition */
- if ((argc == 2) && (id_parse(argv[1], NULL, &dev_type, &dev_num) == 0)) {
+ if ((argc == 2) && (mtd_id_parse(argv[1], NULL, &dev_type, &dev_num) == 0)) {
mtdparts_init();
if (find_dev_and_part(argv[1], &dev, &pnum, &part) == 0) {
if (dev->id->type == MTD_DEV_TYPE_NOR) {
@@ -470,7 +470,7 @@ int do_protect (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
#endif /* CONFIG_SYS_NO_FLASH */
ulong addr_first, addr_last;
int p;
-#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
struct mtd_device *dev;
struct part_info *part;
u8 dev_type, dev_num, pnum;
@@ -563,9 +563,9 @@ int do_protect (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
return rcode;
}
-#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
/* protect on/off <part-id> */
- if ((argc == 3) && (id_parse(argv[2], NULL, &dev_type, &dev_num) == 0)) {
+ if ((argc == 3) && (mtd_id_parse(argv[2], NULL, &dev_type, &dev_num) == 0)) {
mtdparts_init();
if (find_dev_and_part(argv[2], &dev, &pnum, &part) == 0) {
if (dev->id->type == MTD_DEV_TYPE_NOR) {
@@ -698,7 +698,7 @@ int flash_sect_protect (int p, ulong addr_first, ulong addr_last)
/**************************************************/
-#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
# define TMP_ERASE "erase <part-id>\n - erase partition\n"
# define TMP_PROT_ON "protect on <part-id>\n - protect partition\n"
# define TMP_PROT_OFF "protect off <part-id>\n - make partition writable\n"
diff --git a/common/cmd_ide.c b/common/cmd_ide.c
index 8c6ed35..9bc6b4a 100644
--- a/common/cmd_ide.c
+++ b/common/cmd_ide.c
@@ -303,7 +303,7 @@ int do_ide (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
#ifdef CONFIG_SYS_64BIT_LBA
lbaint_t blk = simple_strtoull(argv[3], NULL, 16);
- printf ("\nIDE read: device %d block # %qd, count %ld ... ",
+ printf ("\nIDE read: device %d block # %Ld, count %ld ... ",
curr_device, blk, cnt);
#else
lbaint_t blk = simple_strtoul(argv[3], NULL, 16);
@@ -332,7 +332,7 @@ int do_ide (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
#ifdef CONFIG_SYS_64BIT_LBA
lbaint_t blk = simple_strtoull(argv[3], NULL, 16);
- printf ("\nIDE write: device %d block # %qd, count %ld ... ",
+ printf ("\nIDE write: device %d block # %Ld, count %ld ... ",
curr_device, blk, cnt);
#else
lbaint_t blk = simple_strtoul(argv[3], NULL, 16);
@@ -1315,7 +1315,7 @@ ulong ide_read (int device, lbaint_t blknr, ulong blkcnt, void *buffer)
lba48 = 1;
}
#endif
- debug ("ide_read dev %d start %qX, blocks %lX buffer at %lX\n",
+ debug ("ide_read dev %d start %LX, blocks %lX buffer at %lX\n",
device, blknr, blkcnt, (ulong)buffer);
ide_led (DEVICE_LED(device), 1); /* LED on */
@@ -1403,7 +1403,7 @@ ulong ide_read (int device, lbaint_t blknr, ulong blkcnt, void *buffer)
if ((c&(ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR)) != ATA_STAT_DRQ) {
#if defined(CONFIG_SYS_64BIT_LBA) && defined(CONFIG_SYS_64BIT_VSPRINTF)
- printf ("Error (no IRQ) dev %d blk %qd: status 0x%02x\n",
+ printf ("Error (no IRQ) dev %d blk %Ld: status 0x%02x\n",
device, blknr, c);
#else
printf ("Error (no IRQ) dev %d blk %ld: status 0x%02x\n",
@@ -1493,7 +1493,7 @@ ulong ide_write (int device, lbaint_t blknr, ulong blkcnt, void *buffer)
if ((c&(ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR)) != ATA_STAT_DRQ) {
#if defined(CONFIG_SYS_64BIT_LBA) && defined(CONFIG_SYS_64BIT_VSPRINTF)
- printf ("Error (no IRQ) dev %d blk %qd: status 0x%02x\n",
+ printf ("Error (no IRQ) dev %d blk %Ld: status 0x%02x\n",
device, blknr, c);
#else
printf ("Error (no IRQ) dev %d blk %ld: status 0x%02x\n",
diff --git a/common/cmd_jffs2.c b/common/cmd_jffs2.c
index d0a7cea..860d1d9 100644
--- a/common/cmd_jffs2.c
+++ b/common/cmd_jffs2.c
@@ -136,40 +136,6 @@
* field for read-only partitions */
#define MTD_WRITEABLE_CMD 1
-#ifdef CONFIG_JFFS2_CMDLINE
-/* default values for mtdids and mtdparts variables */
-#if defined(MTDIDS_DEFAULT)
-static const char *const mtdids_default = MTDIDS_DEFAULT;
-#else
-#warning "MTDIDS_DEFAULT not defined!"
-static const char *const mtdids_default = NULL;
-#endif
-
-#if defined(MTDPARTS_DEFAULT)
-static const char *const mtdparts_default = MTDPARTS_DEFAULT;
-#else
-#warning "MTDPARTS_DEFAULT not defined!"
-static const char *const mtdparts_default = NULL;
-#endif
-
-/* copies of last seen 'mtdids', 'mtdparts' and 'partition' env variables */
-#define MTDIDS_MAXLEN 128
-#define MTDPARTS_MAXLEN 512
-#define PARTITION_MAXLEN 16
-static char last_ids[MTDIDS_MAXLEN];
-static char last_parts[MTDPARTS_MAXLEN];
-static char last_partition[PARTITION_MAXLEN];
-
-/* low level jffs2 cache cleaning routine */
-extern void jffs2_free_cache(struct part_info *part);
-
-/* mtdids mapping list, filled by parse_ids() */
-struct list_head mtdids;
-
-/* device/partition list, parse_cmdline() parses into here */
-struct list_head devices;
-#endif /* #ifdef CONFIG_JFFS2_CMDLINE */
-
/* current active device and partition number */
static struct mtd_device *current_dev = NULL;
static u8 current_partnum = 0;
@@ -188,601 +154,14 @@ extern int cramfs_info (struct part_info *info);
#define cramfs_info(x) (0)
#endif
-static struct part_info* jffs2_part_info(struct mtd_device *dev, unsigned int part_num);
-
-/* command line only routines */
-#ifdef CONFIG_JFFS2_CMDLINE
-
-static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_len);
-static int device_del(struct mtd_device *dev);
-
-/**
- * Parses a string into a number. The number stored at ptr is
- * potentially suffixed with K (for kilobytes, or 1024 bytes),
- * M (for megabytes, or 1048576 bytes), or G (for gigabytes, or
- * 1073741824). If the number is suffixed with K, M, or G, then
- * the return value is the number multiplied by one kilobyte, one
- * megabyte, or one gigabyte, respectively.
- *
- * @param ptr where parse begins
- * @param retptr output pointer to next char after parse completes (output)
- * @return resulting unsigned int
- */
-static unsigned long memsize_parse (const char *const ptr, const char **retptr)
-{
- unsigned long ret = simple_strtoul(ptr, (char **)retptr, 0);
-
- switch (**retptr) {
- case 'G':
- case 'g':
- ret <<= 10;
- case 'M':
- case 'm':
- ret <<= 10;
- case 'K':
- case 'k':
- ret <<= 10;
- (*retptr)++;
- default:
- break;
- }
-
- return ret;
-}
-
-/**
- * Format string describing supplied size. This routine does the opposite job
- * to memsize_parse(). Size in bytes is converted to string and if possible
- * shortened by using k (kilobytes), m (megabytes) or g (gigabytes) suffix.
- *
- * Note, that this routine does not check for buffer overflow, it's the caller
- * who must assure enough space.
- *
- * @param buf output buffer
- * @param size size to be converted to string
- */
-static void memsize_format(char *buf, u32 size)
-{
-#define SIZE_GB ((u32)1024*1024*1024)
-#define SIZE_MB ((u32)1024*1024)
-#define SIZE_KB ((u32)1024)
-
- if ((size % SIZE_GB) == 0)
- sprintf(buf, "%ug", size/SIZE_GB);
- else if ((size % SIZE_MB) == 0)
- sprintf(buf, "%um", size/SIZE_MB);
- else if (size % SIZE_KB == 0)
- sprintf(buf, "%uk", size/SIZE_KB);
- else
- sprintf(buf, "%u", size);
-}
-
-/**
- * This routine does global indexing of all partitions. Resulting index for
- * current partition is saved in 'mtddevnum'. Current partition name in
- * 'mtddevname'.
- */
-static void index_partitions(void)
-{
- char buf[16];
- u16 mtddevnum;
- struct part_info *part;
- struct list_head *dentry;
- struct mtd_device *dev;
-
- DEBUGF("--- index partitions ---\n");
-
- if (current_dev) {
- mtddevnum = 0;
- list_for_each(dentry, &devices) {
- dev = list_entry(dentry, struct mtd_device, link);
- if (dev == current_dev) {
- mtddevnum += current_partnum;
- sprintf(buf, "%d", mtddevnum);
- setenv("mtddevnum", buf);
- break;
- }
- mtddevnum += dev->num_parts;
- }
-
- part = jffs2_part_info(current_dev, current_partnum);
- setenv("mtddevname", part->name);
-
- DEBUGF("=> mtddevnum %d,\n=> mtddevname %s\n", mtddevnum, part->name);
- } else {
- setenv("mtddevnum", NULL);
- setenv("mtddevname", NULL);
-
- DEBUGF("=> mtddevnum NULL\n=> mtddevname NULL\n");
- }
-}
-
-/**
- * Save current device and partition in environment variable 'partition'.
- */
-static void current_save(void)
-{
- char buf[16];
-
- DEBUGF("--- current_save ---\n");
-
- if (current_dev) {
- sprintf(buf, "%s%d,%d", MTD_DEV_TYPE(current_dev->id->type),
- current_dev->id->num, current_partnum);
-
- setenv("partition", buf);
- strncpy(last_partition, buf, 16);
-
- DEBUGF("=> partition %s\n", buf);
- } else {
- setenv("partition", NULL);
- last_partition[0] = '\0';
-
- DEBUGF("=> partition NULL\n");
- }
- index_partitions();
-}
-
-/**
- * Performs sanity check for supplied NOR flash partition. Table of existing
- * NOR flash devices is searched and partition device is located. Alignment
- * with the granularity of NOR flash sectors is verified.
- *
- * @param id of the parent device
- * @param part partition to validate
- * @return 0 if partition is valid, 1 otherwise
- */
-static int part_validate_nor(struct mtdids *id, struct part_info *part)
-{
-#if defined(CONFIG_CMD_FLASH)
- /* info for FLASH chips */
- extern flash_info_t flash_info[];
- flash_info_t *flash;
- int offset_aligned;
- u32 end_offset, sector_size = 0;
- int i;
-
- flash = &flash_info[id->num];
-
- /* size of last sector */
- part->sector_size = flash->size -
- (flash->start[flash->sector_count-1] - flash->start[0]);
-
- offset_aligned = 0;
- for (i = 0; i < flash->sector_count; i++) {
- if ((flash->start[i] - flash->start[0]) == part->offset) {
- offset_aligned = 1;
- break;
- }
- }
- if (offset_aligned == 0) {
- printf("%s%d: partition (%s) start offset alignment incorrect\n",
- MTD_DEV_TYPE(id->type), id->num, part->name);
- return 1;
- }
-
- end_offset = part->offset + part->size;
- offset_aligned = 0;
- for (i = 0; i < flash->sector_count; i++) {
- if (i) {
- sector_size = flash->start[i] - flash->start[i-1];
- if (part->sector_size < sector_size)
- part->sector_size = sector_size;
- }
- if ((flash->start[i] - flash->start[0]) == end_offset)
- offset_aligned = 1;
- }
-
- if (offset_aligned || flash->size == end_offset)
- return 0;
-
- printf("%s%d: partition (%s) size alignment incorrect\n",
- MTD_DEV_TYPE(id->type), id->num, part->name);
-#endif
- return 1;
-}
-
-/**
- * Performs sanity check for supplied NAND flash partition. Table of existing
- * NAND flash devices is searched and partition device is located. Alignment
- * with the granularity of nand erasesize is verified.
- *
- * @param id of the parent device
- * @param part partition to validate
- * @return 0 if partition is valid, 1 otherwise
- */
-static int part_validate_nand(struct mtdids *id, struct part_info *part)
-{
-#if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND)
- /* info for NAND chips */
- nand_info_t *nand;
-
- nand = &nand_info[id->num];
-
- part->sector_size = nand->erasesize;
-
- if ((unsigned long)(part->offset) % nand->erasesize) {
- printf("%s%d: partition (%s) start offset alignment incorrect\n",
- MTD_DEV_TYPE(id->type), id->num, part->name);
- return 1;
- }
-
- if (part->size % nand->erasesize) {
- printf("%s%d: partition (%s) size alignment incorrect\n",
- MTD_DEV_TYPE(id->type), id->num, part->name);
- return 1;
- }
-
- return 0;
-#else
- return 1;
-#endif
-}
-
-/**
- * Performs sanity check for supplied OneNAND flash partition.
- * Table of existing OneNAND flash devices is searched and partition device
- * is located. Alignment with the granularity of nand erasesize is verified.
- *
- * @param id of the parent device
- * @param part partition to validate
- * @return 0 if partition is valid, 1 otherwise
- */
-static int part_validate_onenand(struct mtdids *id, struct part_info *part)
-{
-#if defined(CONFIG_CMD_ONENAND)
- /* info for OneNAND chips */
- struct mtd_info *mtd;
-
- mtd = &onenand_mtd;
-
- part->sector_size = mtd->erasesize;
-
- if ((unsigned long)(part->offset) % mtd->erasesize) {
- printf("%s%d: partition (%s) start offset"
- "alignment incorrect\n",
- MTD_DEV_TYPE(id->type), id->num, part->name);
- return 1;
- }
-
- if (part->size % mtd->erasesize) {
- printf("%s%d: partition (%s) size alignment incorrect\n",
- MTD_DEV_TYPE(id->type), id->num, part->name);
- return 1;
- }
-
- return 0;
-#else
- return 1;
-#endif
-}
-
-
-/**
- * Performs sanity check for supplied partition. Offset and size are verified
- * to be within valid range. Partition type is checked and either
- * parts_validate_nor() or parts_validate_nand() is called with the argument
- * of part.
- *
- * @param id of the parent device
- * @param part partition to validate
- * @return 0 if partition is valid, 1 otherwise
- */
-static int part_validate(struct mtdids *id, struct part_info *part)
-{
- if (part->size == SIZE_REMAINING)
- part->size = id->size - part->offset;
-
- if (part->offset > id->size) {
- printf("%s: offset %08x beyond flash size %08x\n",
- id->mtd_id, part->offset, id->size);
- return 1;
- }
-
- if ((part->offset + part->size) <= part->offset) {
- printf("%s%d: partition (%s) size too big\n",
- MTD_DEV_TYPE(id->type), id->num, part->name);
- return 1;
- }
-
- if (part->offset + part->size > id->size) {
- printf("%s: partitioning exceeds flash size\n", id->mtd_id);
- return 1;
- }
-
- if (id->type == MTD_DEV_TYPE_NAND)
- return part_validate_nand(id, part);
- else if (id->type == MTD_DEV_TYPE_NOR)
- return part_validate_nor(id, part);
- else if (id->type == MTD_DEV_TYPE_ONENAND)
- return part_validate_onenand(id, part);
- else
- DEBUGF("part_validate: invalid dev type\n");
-
- return 1;
-}
-
-/**
- * Delete selected partition from the partion list of the specified device.
- *
- * @param dev device to delete partition from
- * @param part partition to delete
- * @return 0 on success, 1 otherwise
- */
-static int part_del(struct mtd_device *dev, struct part_info *part)
-{
- u8 current_save_needed = 0;
-
- /* if there is only one partition, remove whole device */
- if (dev->num_parts == 1)
- return device_del(dev);
-
- /* otherwise just delete this partition */
-
- if (dev == current_dev) {
- /* we are modyfing partitions for the current device,
- * update current */
- struct part_info *curr_pi;
- curr_pi = jffs2_part_info(current_dev, current_partnum);
-
- if (curr_pi) {
- if (curr_pi == part) {
- printf("current partition deleted, resetting current to 0\n");
- current_partnum = 0;
- } else if (part->offset <= curr_pi->offset) {
- current_partnum--;
- }
- current_save_needed = 1;
- }
- }
-
-#ifdef CONFIG_NAND_LEGACY
- jffs2_free_cache(part);
-#endif
- list_del(&part->link);
- free(part);
- dev->num_parts--;
-
- if (current_save_needed > 0)
- current_save();
- else
- index_partitions();
-
- return 0;
-}
-
-/**
- * Delete all partitions from parts head list, free memory.
- *
- * @param head list of partitions to delete
- */
-static void part_delall(struct list_head *head)
-{
- struct list_head *entry, *n;
- struct part_info *part_tmp;
-
- /* clean tmp_list and free allocated memory */
- list_for_each_safe(entry, n, head) {
- part_tmp = list_entry(entry, struct part_info, link);
-
-#ifdef CONFIG_NAND_LEGACY
- jffs2_free_cache(part_tmp);
-#endif
- list_del(entry);
- free(part_tmp);
- }
-}
-
-/**
- * Add new partition to the supplied partition list. Make sure partitions are
- * sorted by offset in ascending order.
- *
- * @param head list this partition is to be added to
- * @param new partition to be added
- */
-static int part_sort_add(struct mtd_device *dev, struct part_info *part)
-{
- struct list_head *entry;
- struct part_info *new_pi, *curr_pi;
-
- /* link partition to parrent dev */
- part->dev = dev;
-
- if (list_empty(&dev->parts)) {
- DEBUGF("part_sort_add: list empty\n");
- list_add(&part->link, &dev->parts);
- dev->num_parts++;
- index_partitions();
- return 0;
- }
-
- new_pi = list_entry(&part->link, struct part_info, link);
-
- /* get current partition info if we are updating current device */
- curr_pi = NULL;
- if (dev == current_dev)
- curr_pi = jffs2_part_info(current_dev, current_partnum);
-
- list_for_each(entry, &dev->parts) {
- struct part_info *pi;
-
- pi = list_entry(entry, struct part_info, link);
-
- /* be compliant with kernel cmdline, allow only one partition at offset zero */
- if ((new_pi->offset == pi->offset) && (pi->offset == 0)) {
- printf("cannot add second partition at offset 0\n");
- return 1;
- }
-
- if (new_pi->offset <= pi->offset) {
- list_add_tail(&part->link, entry);
- dev->num_parts++;
-
- if (curr_pi && (pi->offset <= curr_pi->offset)) {
- /* we are modyfing partitions for the current
- * device, update current */
- current_partnum++;
- current_save();
- } else {
- index_partitions();
- }
- return 0;
- }
- }
-
- list_add_tail(&part->link, &dev->parts);
- dev->num_parts++;
- index_partitions();
- return 0;
-}
-
-/**
- * Add provided partition to the partition list of a given device.
- *
- * @param dev device to which partition is added
- * @param part partition to be added
- * @return 0 on success, 1 otherwise
- */
-static int part_add(struct mtd_device *dev, struct part_info *part)
-{
- /* verify alignment and size */
- if (part_validate(dev->id, part) != 0)
- return 1;
-
- /* partition is ok, add it to the list */
- if (part_sort_add(dev, part) != 0)
- return 1;
-
- return 0;
-}
-
-/**
- * Parse one partition definition, allocate memory and return pointer to this
- * location in retpart.
- *
- * @param partdef pointer to the partition definition string i.e. <part-def>
- * @param ret output pointer to next char after parse completes (output)
- * @param retpart pointer to the allocated partition (output)
- * @return 0 on success, 1 otherwise
- */
-static int part_parse(const char *const partdef, const char **ret, struct part_info **retpart)
-{
- struct part_info *part;
- unsigned long size;
- unsigned long offset;
- const char *name;
- int name_len;
- unsigned int mask_flags;
- const char *p;
-
- p = partdef;
- *retpart = NULL;
- *ret = NULL;
-
- /* fetch the partition size */
- if (*p == '-') {
- /* assign all remaining space to this partition */
- DEBUGF("'-': remaining size assigned\n");
- size = SIZE_REMAINING;
- p++;
- } else {
- size = memsize_parse(p, &p);
- if (size < MIN_PART_SIZE) {
- printf("partition size too small (%lx)\n", size);
- return 1;
- }
- }
-
- /* check for offset */
- offset = OFFSET_NOT_SPECIFIED;
- if (*p == '@') {
- p++;
- offset = memsize_parse(p, &p);
- }
-
- /* now look for the name */
- if (*p == '(') {
- name = ++p;
- if ((p = strchr(name, ')')) == NULL) {
- printf("no closing ) found in partition name\n");
- return 1;
- }
- name_len = p - name + 1;
- if ((name_len - 1) == 0) {
- printf("empty partition name\n");
- return 1;
- }
- p++;
- } else {
- /* 0x00000000@0x00000000 */
- name_len = 22;
- name = NULL;
- }
-
- /* test for options */
- mask_flags = 0;
- if (strncmp(p, "ro", 2) == 0) {
- mask_flags |= MTD_WRITEABLE_CMD;
- p += 2;
- }
-
- /* check for next partition definition */
- if (*p == ',') {
- if (size == SIZE_REMAINING) {
- *ret = NULL;
- printf("no partitions allowed after a fill-up partition\n");
- return 1;
- }
- *ret = ++p;
- } else if ((*p == ';') || (*p == '\0')) {
- *ret = p;
- } else {
- printf("unexpected character '%c' at the end of partition\n", *p);
- *ret = NULL;
- return 1;
- }
-
- /* allocate memory */
- part = (struct part_info *)malloc(sizeof(struct part_info) + name_len);
- if (!part) {
- printf("out of memory\n");
- return 1;
- }
- memset(part, 0, sizeof(struct part_info) + name_len);
- part->size = size;
- part->offset = offset;
- part->mask_flags = mask_flags;
- part->name = (char *)(part + 1);
-
- if (name) {
- /* copy user provided name */
- strncpy(part->name, name, name_len - 1);
- part->auto_name = 0;
- } else {
- /* auto generated name in form of size@offset */
- sprintf(part->name, "0x%08lx@0x%08lx", size, offset);
- part->auto_name = 1;
- }
-
- part->name[name_len - 1] = '\0';
- INIT_LIST_HEAD(&part->link);
-
- DEBUGF("+ partition: name %-22s size 0x%08x offset 0x%08x mask flags %d\n",
- part->name, part->size,
- part->offset, part->mask_flags);
-
- *retpart = part;
- return 0;
-}
-#endif/* #ifdef CONFIG_JFFS2_CMDLINE */
-
+#ifndef CONFIG_CMD_MTDPARTS
/**
* Check device number to be within valid range for given device type.
*
* @param dev device to validate
* @return 0 if device is valid, 1 otherwise
*/
-static int device_validate(u8 type, u8 num, u32 *size)
+static int mtd_device_validate(u8 type, u8 num, u32 *size)
{
if (type == MTD_DEV_TYPE_NOR) {
#if defined(CONFIG_CMD_FLASH)
@@ -828,310 +207,6 @@ static int device_validate(u8 type, u8 num, u32 *size)
return 1;
}
-#ifdef CONFIG_JFFS2_CMDLINE
-/**
- * Delete all mtd devices from a supplied devices list, free memory allocated for
- * each device and delete all device partitions.
- *
- * @return 0 on success, 1 otherwise
- */
-static int device_delall(struct list_head *head)
-{
- struct list_head *entry, *n;
- struct mtd_device *dev_tmp;
-
- /* clean devices list */
- list_for_each_safe(entry, n, head) {
- dev_tmp = list_entry(entry, struct mtd_device, link);
- list_del(entry);
- part_delall(&dev_tmp->parts);
- free(dev_tmp);
- }
- INIT_LIST_HEAD(&devices);
-
- return 0;
-}
-
-/**
- * If provided device exists it's partitions are deleted, device is removed
- * from device list and device memory is freed.
- *
- * @param dev device to be deleted
- * @return 0 on success, 1 otherwise
- */
-static int device_del(struct mtd_device *dev)
-{
- part_delall(&dev->parts);
- list_del(&dev->link);
- free(dev);
-
- if (dev == current_dev) {
- /* we just deleted current device */
- if (list_empty(&devices)) {
- current_dev = NULL;
- } else {
- /* reset first partition from first dev from the
- * devices list as current */
- current_dev = list_entry(devices.next, struct mtd_device, link);
- current_partnum = 0;
- }
- current_save();
- return 0;
- }
-
- index_partitions();
- return 0;
-}
-
-/**
- * Search global device list and return pointer to the device of type and num
- * specified.
- *
- * @param type device type
- * @param num device number
- * @return NULL if requested device does not exist
- */
-static struct mtd_device* device_find(u8 type, u8 num)
-{
- struct list_head *entry;
- struct mtd_device *dev_tmp;
-
- list_for_each(entry, &devices) {
- dev_tmp = list_entry(entry, struct mtd_device, link);
-
- if ((dev_tmp->id->type == type) && (dev_tmp->id->num == num))
- return dev_tmp;
- }
-
- return NULL;
-}
-
-/**
- * Add specified device to the global device list.
- *
- * @param dev device to be added
- */
-static void device_add(struct mtd_device *dev)
-{
- u8 current_save_needed = 0;
-
- if (list_empty(&devices)) {
- current_dev = dev;
- current_partnum = 0;
- current_save_needed = 1;
- }
-
- list_add_tail(&dev->link, &devices);
-
- if (current_save_needed > 0)
- current_save();
- else
- index_partitions();
-}
-
-/**
- * Parse device type, name and mtd-id. If syntax is ok allocate memory and
- * return pointer to the device structure.
- *
- * @param mtd_dev pointer to the device definition string i.e. <mtd-dev>
- * @param ret output pointer to next char after parse completes (output)
- * @param retdev pointer to the allocated device (output)
- * @return 0 on success, 1 otherwise
- */
-static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_device **retdev)
-{
- struct mtd_device *dev;
- struct part_info *part;
- struct mtdids *id;
- const char *mtd_id;
- unsigned int mtd_id_len;
- const char *p, *pend;
- LIST_HEAD(tmp_list);
- struct list_head *entry, *n;
- u16 num_parts;
- u32 offset;
- int err = 1;
-
- p = mtd_dev;
- *retdev = NULL;
- *ret = NULL;
-
- DEBUGF("===device_parse===\n");
-
- /* fetch <mtd-id> */
- mtd_id = p;
- if (!(p = strchr(mtd_id, ':'))) {
- printf("no <mtd-id> identifier\n");
- return 1;
- }
- mtd_id_len = p - mtd_id + 1;
- p++;
-
- /* verify if we have a valid device specified */
- if ((id = id_find_by_mtd_id(mtd_id, mtd_id_len - 1)) == NULL) {
- printf("invalid mtd device '%.*s'\n", mtd_id_len - 1, mtd_id);
- return 1;
- }
-
- DEBUGF("dev type = %d (%s), dev num = %d, mtd-id = %s\n",
- id->type, MTD_DEV_TYPE(id->type),
- id->num, id->mtd_id);
- pend = strchr(p, ';');
- DEBUGF("parsing partitions %.*s\n", (pend ? pend - p : strlen(p)), p);
-
-
- /* parse partitions */
- num_parts = 0;
-
- offset = 0;
- if ((dev = device_find(id->type, id->num)) != NULL) {
- /* if device already exists start at the end of the last partition */
- part = list_entry(dev->parts.prev, struct part_info, link);
- offset = part->offset + part->size;
- }
-
- while (p && (*p != '\0') && (*p != ';')) {
- err = 1;
- if ((part_parse(p, &p, &part) != 0) || (!part))
- break;
-
- /* calculate offset when not specified */
- if (part->offset == OFFSET_NOT_SPECIFIED)
- part->offset = offset;
- else
- offset = part->offset;
-
- /* verify alignment and size */
- if (part_validate(id, part) != 0)
- break;
-
- offset += part->size;
-
- /* partition is ok, add it to the list */
- list_add_tail(&part->link, &tmp_list);
- num_parts++;
- err = 0;
- }
- if (err == 1) {
- part_delall(&tmp_list);
- return 1;
- }
-
- if (num_parts == 0) {
- printf("no partitions for device %s%d (%s)\n",
- MTD_DEV_TYPE(id->type), id->num, id->mtd_id);
- return 1;
- }
-
- DEBUGF("\ntotal partitions: %d\n", num_parts);
-
- /* check for next device presence */
- if (p) {
- if (*p == ';') {
- *ret = ++p;
- } else if (*p == '\0') {
- *ret = p;
- } else {
- printf("unexpected character '%c' at the end of device\n", *p);
- *ret = NULL;
- return 1;
- }
- }
-
- /* allocate memory for mtd_device structure */
- if ((dev = (struct mtd_device *)malloc(sizeof(struct mtd_device))) == NULL) {
- printf("out of memory\n");
- return 1;
- }
- memset(dev, 0, sizeof(struct mtd_device));
- dev->id = id;
- dev->num_parts = 0; /* part_sort_add increments num_parts */
- INIT_LIST_HEAD(&dev->parts);
- INIT_LIST_HEAD(&dev->link);
-
- /* move partitions from tmp_list to dev->parts */
- list_for_each_safe(entry, n, &tmp_list) {
- part = list_entry(entry, struct part_info, link);
- list_del(entry);
- if (part_sort_add(dev, part) != 0) {
- device_del(dev);
- return 1;
- }
- }
-
- *retdev = dev;
-
- DEBUGF("===\n\n");
- return 0;
-}
-
-/**
- * Initialize global device list.
- *
- * @return 0 on success, 1 otherwise
- */
-static int jffs2_devices_init(void)
-{
- last_parts[0] = '\0';
- current_dev = NULL;
- current_save();
-
- return device_delall(&devices);
-}
-
-/*
- * Search global mtdids list and find id of requested type and number.
- *
- * @return pointer to the id if it exists, NULL otherwise
- */
-static struct mtdids* id_find(u8 type, u8 num)
-{
- struct list_head *entry;
- struct mtdids *id;
-
- list_for_each(entry, &mtdids) {
- id = list_entry(entry, struct mtdids, link);
-
- if ((id->type == type) && (id->num == num))
- return id;
- }
-
- return NULL;
-}
-
-/**
- * Search global mtdids list and find id of a requested mtd_id.
- *
- * Note: first argument is not null terminated.
- *
- * @param mtd_id string containing requested mtd_id
- * @param mtd_id_len length of supplied mtd_id
- * @return pointer to the id if it exists, NULL otherwise
- */
-static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_len)
-{
- struct list_head *entry;
- struct mtdids *id;
-
- DEBUGF("--- id_find_by_mtd_id: '%.*s' (len = %d)\n",
- mtd_id_len, mtd_id, mtd_id_len);
-
- list_for_each(entry, &mtdids) {
- id = list_entry(entry, struct mtdids, link);
-
- DEBUGF("entry: '%s' (len = %d)\n",
- id->mtd_id, strlen(id->mtd_id));
-
- if (mtd_id_len != strlen(id->mtd_id))
- continue;
- if (strncmp(id->mtd_id, mtd_id, mtd_id_len) == 0)
- return id;
- }
-
- return NULL;
-}
-#endif /* #ifdef CONFIG_JFFS2_CMDLINE */
-
/**
* Parse device id string <dev-id> := 'nand'|'nor'|'onenand'<dev-num>,
* return device type and number.
@@ -1142,7 +217,7 @@ static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_
* @param dev_num parsed device number (output)
* @return 0 on success, 1 otherwise
*/
-int id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num)
+static int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num)
{
const char *p = id;
@@ -1172,606 +247,6 @@ int id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num)
return 0;
}
-#ifdef CONFIG_JFFS2_CMDLINE
-/**
- * Process all devices and generate corresponding mtdparts string describing
- * all partitions on all devices.
- *
- * @param buf output buffer holding generated mtdparts string (output)
- * @param buflen buffer size
- * @return 0 on success, 1 otherwise
- */
-static int generate_mtdparts(char *buf, u32 buflen)
-{
- struct list_head *pentry, *dentry;
- struct mtd_device *dev;
- struct part_info *part, *prev_part;
- char *p = buf;
- char tmpbuf[32];
- u32 size, offset, len, part_cnt;
- u32 maxlen = buflen - 1;
-
- DEBUGF("--- generate_mtdparts ---\n");
-
- if (list_empty(&devices)) {
- buf[0] = '\0';
- return 0;
- }
-
- sprintf(p, "mtdparts=");
- p += 9;
-
- list_for_each(dentry, &devices) {
- dev = list_entry(dentry, struct mtd_device, link);
-
- /* copy mtd_id */
- len = strlen(dev->id->mtd_id) + 1;
- if (len > maxlen)
- goto cleanup;
- memcpy(p, dev->id->mtd_id, len - 1);
- p += len - 1;
- *(p++) = ':';
- maxlen -= len;
-
- /* format partitions */
- prev_part = NULL;
- part_cnt = 0;
- list_for_each(pentry, &dev->parts) {
- part = list_entry(pentry, struct part_info, link);
- size = part->size;
- offset = part->offset;
- part_cnt++;
-
- /* partition size */
- memsize_format(tmpbuf, size);
- len = strlen(tmpbuf);
- if (len > maxlen)
- goto cleanup;
- memcpy(p, tmpbuf, len);
- p += len;
- maxlen -= len;
-
-
- /* add offset only when there is a gap between
- * partitions */
- if ((!prev_part && (offset != 0)) ||
- (prev_part && ((prev_part->offset + prev_part->size) != part->offset))) {
-
- memsize_format(tmpbuf, offset);
- len = strlen(tmpbuf) + 1;
- if (len > maxlen)
- goto cleanup;
- *(p++) = '@';
- memcpy(p, tmpbuf, len - 1);
- p += len - 1;
- maxlen -= len;
- }
-
- /* copy name only if user supplied */
- if(!part->auto_name) {
- len = strlen(part->name) + 2;
- if (len > maxlen)
- goto cleanup;
-
- *(p++) = '(';
- memcpy(p, part->name, len - 2);
- p += len - 2;
- *(p++) = ')';
- maxlen -= len;
- }
-
- /* ro mask flag */
- if (part->mask_flags && MTD_WRITEABLE_CMD) {
- len = 2;
- if (len > maxlen)
- goto cleanup;
- *(p++) = 'r';
- *(p++) = 'o';
- maxlen -= 2;
- }
-
- /* print ',' separator if there are other partitions
- * following */
- if (dev->num_parts > part_cnt) {
- if (1 > maxlen)
- goto cleanup;
- *(p++) = ',';
- maxlen--;
- }
- prev_part = part;
- }
- /* print ';' separator if there are other devices following */
- if (dentry->next != &devices) {
- if (1 > maxlen)
- goto cleanup;
- *(p++) = ';';
- maxlen--;
- }
- }
-
- /* we still have at least one char left, as we decremented maxlen at
- * the begining */
- *p = '\0';
-
- return 0;
-
-cleanup:
- last_parts[0] = '\0';
- return 1;
-}
-
-/**
- * Call generate_mtdparts to process all devices and generate corresponding
- * mtdparts string, save it in mtdparts environment variable.
- *
- * @param buf output buffer holding generated mtdparts string (output)
- * @param buflen buffer size
- * @return 0 on success, 1 otherwise
- */
-static int generate_mtdparts_save(char *buf, u32 buflen)
-{
- int ret;
-
- ret = generate_mtdparts(buf, buflen);
-
- if ((buf[0] != '\0') && (ret == 0))
- setenv("mtdparts", buf);
- else
- setenv("mtdparts", NULL);
-
- return ret;
-}
-
-/**
- * Format and print out a partition list for each device from global device
- * list.
- */
-static void list_partitions(void)
-{
- struct list_head *dentry, *pentry;
- struct part_info *part;
- struct mtd_device *dev;
- int part_num;
-
- DEBUGF("\n---list_partitions---\n");
- list_for_each(dentry, &devices) {
- dev = list_entry(dentry, struct mtd_device, link);
- printf("\ndevice %s%d <%s>, # parts = %d\n",
- MTD_DEV_TYPE(dev->id->type), dev->id->num,
- dev->id->mtd_id, dev->num_parts);
- printf(" #: name\t\t\tsize\t\toffset\t\tmask_flags\n");
-
- /* list partitions for given device */
- part_num = 0;
- list_for_each(pentry, &dev->parts) {
- part = list_entry(pentry, struct part_info, link);
- printf("%2d: %-20s0x%08x\t0x%08x\t%d\n",
- part_num, part->name, part->size,
- part->offset, part->mask_flags);
-
- part_num++;
- }
- }
- if (list_empty(&devices))
- printf("no partitions defined\n");
-
- /* current_dev is not NULL only when we have non empty device list */
- if (current_dev) {
- part = jffs2_part_info(current_dev, current_partnum);
- if (part) {
- printf("\nactive partition: %s%d,%d - (%s) 0x%08x @ 0x%08x\n",
- MTD_DEV_TYPE(current_dev->id->type),
- current_dev->id->num, current_partnum,
- part->name, part->size, part->offset);
- } else {
- printf("could not get current partition info\n\n");
- }
- }
-
- printf("\ndefaults:\n");
- printf("mtdids : %s\n", mtdids_default);
- printf("mtdparts: %s\n", mtdparts_default);
-}
-
-/**
- * Given partition identifier in form of <dev_type><dev_num>,<part_num> find
- * corresponding device and verify partition number.
- *
- * @param id string describing device and partition or partition name
- * @param dev pointer to the requested device (output)
- * @param part_num verified partition number (output)
- * @param part pointer to requested partition (output)
- * @return 0 on success, 1 otherwise
- */
-int find_dev_and_part(const char *id, struct mtd_device **dev,
- u8 *part_num, struct part_info **part)
-{
- struct list_head *dentry, *pentry;
- u8 type, dnum, pnum;
- const char *p;
-
- DEBUGF("--- find_dev_and_part ---\nid = %s\n", id);
-
- list_for_each(dentry, &devices) {
- *part_num = 0;
- *dev = list_entry(dentry, struct mtd_device, link);
- list_for_each(pentry, &(*dev)->parts) {
- *part = list_entry(pentry, struct part_info, link);
- if (strcmp((*part)->name, id) == 0)
- return 0;
- (*part_num)++;
- }
- }
-
- p = id;
- *dev = NULL;
- *part = NULL;
- *part_num = 0;
-
- if (id_parse(p, &p, &type, &dnum) != 0)
- return 1;
-
- if ((*p++ != ',') || (*p == '\0')) {
- printf("no partition number specified\n");
- return 1;
- }
- pnum = simple_strtoul(p, (char **)&p, 0);
- if (*p != '\0') {
- printf("unexpected trailing character '%c'\n", *p);
- return 1;
- }
-
- if ((*dev = device_find(type, dnum)) == NULL) {
- printf("no such device %s%d\n", MTD_DEV_TYPE(type), dnum);
- return 1;
- }
-
- if ((*part = jffs2_part_info(*dev, pnum)) == NULL) {
- printf("no such partition\n");
- *dev = NULL;
- return 1;
- }
-
- *part_num = pnum;
-
- return 0;
-}
-
-/**
- * Find and delete partition. For partition id format see find_dev_and_part().
- *
- * @param id string describing device and partition
- * @return 0 on success, 1 otherwise
- */
-static int delete_partition(const char *id)
-{
- u8 pnum;
- struct mtd_device *dev;
- struct part_info *part;
-
- if (find_dev_and_part(id, &dev, &pnum, &part) == 0) {
-
- DEBUGF("delete_partition: device = %s%d, partition %d = (%s) 0x%08lx@0x%08lx\n",
- MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum,
- part->name, part->size, part->offset);
-
- if (part_del(dev, part) != 0)
- return 1;
-
- if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) {
- printf("generated mtdparts too long, reseting to null\n");
- return 1;
- }
- return 0;
- }
-
- printf("partition %s not found\n", id);
- return 1;
-}
-
-/**
- * Accept character string describing mtd partitions and call device_parse()
- * for each entry. Add created devices to the global devices list.
- *
- * @param mtdparts string specifing mtd partitions
- * @return 0 on success, 1 otherwise
- */
-static int parse_mtdparts(const char *const mtdparts)
-{
- const char *p = mtdparts;
- struct mtd_device *dev;
- int err = 1;
-
- DEBUGF("\n---parse_mtdparts---\nmtdparts = %s\n\n", p);
-
- /* delete all devices and partitions */
- if (jffs2_devices_init() != 0) {
- printf("could not initialise device list\n");
- return err;
- }
-
- /* re-read 'mtdparts' variable, jffs2_devices_init may be updating env */
- p = getenv("mtdparts");
-
- if (strncmp(p, "mtdparts=", 9) != 0) {
- printf("mtdparts variable doesn't start with 'mtdparts='\n");
- return err;
- }
- p += 9;
-
- while (p && (*p != '\0')) {
- err = 1;
- if ((device_parse(p, &p, &dev) != 0) || (!dev))
- break;
-
- DEBUGF("+ device: %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type),
- dev->id->num, dev->id->mtd_id);
-
- /* check if parsed device is already on the list */
- if (device_find(dev->id->type, dev->id->num) != NULL) {
- printf("device %s%d redefined, please correct mtdparts variable\n",
- MTD_DEV_TYPE(dev->id->type), dev->id->num);
- break;
- }
-
- list_add_tail(&dev->link, &devices);
- err = 0;
- }
- if (err == 1) {
- device_delall(&devices);
- return 1;
- }
-
- return 0;
-}
-
-/**
- * Parse provided string describing mtdids mapping (see file header for mtdids
- * variable format). Allocate memory for each entry and add all found entries
- * to the global mtdids list.
- *
- * @param ids mapping string
- * @return 0 on success, 1 otherwise
- */
-static int parse_mtdids(const char *const ids)
-{
- const char *p = ids;
- const char *mtd_id;
- int mtd_id_len;
- struct mtdids *id;
- struct list_head *entry, *n;
- struct mtdids *id_tmp;
- u8 type, num;
- u32 size;
- int ret = 1;
-
- DEBUGF("\n---parse_mtdids---\nmtdids = %s\n\n", ids);
-
- /* clean global mtdids list */
- list_for_each_safe(entry, n, &mtdids) {
- id_tmp = list_entry(entry, struct mtdids, link);
- DEBUGF("mtdids del: %d %d\n", id_tmp->type, id_tmp->num);
- list_del(entry);
- free(id_tmp);
- }
- last_ids[0] = '\0';
- INIT_LIST_HEAD(&mtdids);
-
- while(p && (*p != '\0')) {
-
- ret = 1;
- /* parse 'nor'|'nand'|'onenand'<dev-num> */
- if (id_parse(p, &p, &type, &num) != 0)
- break;
-
- if (*p != '=') {
- printf("mtdids: incorrect <dev-num>\n");
- break;
- }
- p++;
-
- /* check if requested device exists */
- if (device_validate(type, num, &size) != 0)
- return 1;
-
- /* locate <mtd-id> */
- mtd_id = p;
- if ((p = strchr(mtd_id, ',')) != NULL) {
- mtd_id_len = p - mtd_id + 1;
- p++;
- } else {
- mtd_id_len = strlen(mtd_id) + 1;
- }
- if (mtd_id_len == 0) {
- printf("mtdids: no <mtd-id> identifier\n");
- break;
- }
-
- /* check if this id is already on the list */
- int double_entry = 0;
- list_for_each(entry, &mtdids) {
- id_tmp = list_entry(entry, struct mtdids, link);
- if ((id_tmp->type == type) && (id_tmp->num == num)) {
- double_entry = 1;
- break;
- }
- }
- if (double_entry) {
- printf("device id %s%d redefined, please correct mtdids variable\n",
- MTD_DEV_TYPE(type), num);
- break;
- }
-
- /* allocate mtdids structure */
- if (!(id = (struct mtdids *)malloc(sizeof(struct mtdids) + mtd_id_len))) {
- printf("out of memory\n");
- break;
- }
- memset(id, 0, sizeof(struct mtdids) + mtd_id_len);
- id->num = num;
- id->type = type;
- id->size = size;
- id->mtd_id = (char *)(id + 1);
- strncpy(id->mtd_id, mtd_id, mtd_id_len - 1);
- id->mtd_id[mtd_id_len - 1] = '\0';
- INIT_LIST_HEAD(&id->link);
-
- DEBUGF("+ id %s%d\t%16d bytes\t%s\n",
- MTD_DEV_TYPE(id->type), id->num,
- id->size, id->mtd_id);
-
- list_add_tail(&id->link, &mtdids);
- ret = 0;
- }
- if (ret == 1) {
- /* clean mtdids list and free allocated memory */
- list_for_each_safe(entry, n, &mtdids) {
- id_tmp = list_entry(entry, struct mtdids, link);
- list_del(entry);
- free(id_tmp);
- }
- return 1;
- }
-
- return 0;
-}
-
-/**
- * Parse and initialize global mtdids mapping and create global
- * device/partition list.
- *
- * @return 0 on success, 1 otherwise
- */
-int mtdparts_init(void)
-{
- static int initialized = 0;
- const char *ids, *parts;
- const char *current_partition;
- int ids_changed;
- char tmp_ep[PARTITION_MAXLEN];
-
- DEBUGF("\n---mtdparts_init---\n");
- if (!initialized) {
- INIT_LIST_HEAD(&mtdids);
- INIT_LIST_HEAD(&devices);
- memset(last_ids, 0, MTDIDS_MAXLEN);
- memset(last_parts, 0, MTDPARTS_MAXLEN);
- memset(last_partition, 0, PARTITION_MAXLEN);
- initialized = 1;
- }
-
- /* get variables */
- ids = getenv("mtdids");
- parts = getenv("mtdparts");
- current_partition = getenv("partition");
-
- /* save it for later parsing, cannot rely on current partition pointer
- * as 'partition' variable may be updated during init */
- tmp_ep[0] = '\0';
- if (current_partition)
- strncpy(tmp_ep, current_partition, PARTITION_MAXLEN);
-
- DEBUGF("last_ids : %s\n", last_ids);
- DEBUGF("env_ids : %s\n", ids);
- DEBUGF("last_parts: %s\n", last_parts);
- DEBUGF("env_parts : %s\n\n", parts);
-
- DEBUGF("last_partition : %s\n", last_partition);
- DEBUGF("env_partition : %s\n", current_partition);
-
- /* if mtdids varible is empty try to use defaults */
- if (!ids) {
- if (mtdids_default) {
- DEBUGF("mtdids variable not defined, using default\n");
- ids = mtdids_default;
- setenv("mtdids", (char *)ids);
- } else {
- printf("mtdids not defined, no default present\n");
- return 1;
- }
- }
- if (strlen(ids) > MTDIDS_MAXLEN - 1) {
- printf("mtdids too long (> %d)\n", MTDIDS_MAXLEN);
- return 1;
- }
-
- /* do no try to use defaults when mtdparts variable is not defined,
- * just check the length */
- if (!parts)
- printf("mtdparts variable not set, see 'help mtdparts'\n");
-
- if (parts && (strlen(parts) > MTDPARTS_MAXLEN - 1)) {
- printf("mtdparts too long (> %d)\n", MTDPARTS_MAXLEN);
- return 1;
- }
-
- /* check if we have already parsed those mtdids */
- if ((last_ids[0] != '\0') && (strcmp(last_ids, ids) == 0)) {
- ids_changed = 0;
- } else {
- ids_changed = 1;
-
- if (parse_mtdids(ids) != 0) {
- jffs2_devices_init();
- return 1;
- }
-
- /* ok it's good, save new ids */
- strncpy(last_ids, ids, MTDIDS_MAXLEN);
- }
-
- /* parse partitions if either mtdparts or mtdids were updated */
- if (parts && ((last_parts[0] == '\0') || ((strcmp(last_parts, parts) != 0)) || ids_changed)) {
- if (parse_mtdparts(parts) != 0)
- return 1;
-
- if (list_empty(&devices)) {
- printf("mtdparts_init: no valid partitions\n");
- return 1;
- }
-
- /* ok it's good, save new parts */
- strncpy(last_parts, parts, MTDPARTS_MAXLEN);
-
- /* reset first partition from first dev from the list as current */
- current_dev = list_entry(devices.next, struct mtd_device, link);
- current_partnum = 0;
- current_save();
-
- DEBUGF("mtdparts_init: current_dev = %s%d, current_partnum = %d\n",
- MTD_DEV_TYPE(current_dev->id->type),
- current_dev->id->num, current_partnum);
- }
-
- /* mtdparts variable was reset to NULL, delete all devices/partitions */
- if (!parts && (last_parts[0] != '\0'))
- return jffs2_devices_init();
-
- /* do not process current partition if mtdparts variable is null */
- if (!parts)
- return 0;
-
- /* is current partition set in environment? if so, use it */
- if ((tmp_ep[0] != '\0') && (strcmp(tmp_ep, last_partition) != 0)) {
- struct part_info *p;
- struct mtd_device *cdev;
- u8 pnum;
-
- DEBUGF("--- getting current partition: %s\n", tmp_ep);
-
- if (find_dev_and_part(tmp_ep, &cdev, &pnum, &p) == 0) {
- current_dev = cdev;
- current_partnum = pnum;
- current_save();
- }
- } else if (getenv("partition") == NULL) {
- DEBUGF("no partition variable set, setting...\n");
- current_save();
- }
-
- return 0;
-}
-#else /* #ifdef CONFIG_JFFS2_CMDLINE */
/*
* 'Static' version of command line mtdparts_init() routine. Single partition on
* a single device configuration.
@@ -1908,8 +383,8 @@ int mtdparts_init(void)
dev_name = "nor0";
#endif
- if ((id_parse(dev_name, NULL, &id->type, &id->num) != 0) ||
- (device_validate(id->type, id->num, &size) != 0)) {
+ if ((mtd_id_parse(dev_name, NULL, &id->type, &id->num) != 0) ||
+ (mtd_device_validate(id->type, id->num, &size) != 0)) {
printf("incorrect device: %s%d\n", MTD_DEV_TYPE(id->type), id->num);
free(current_dev);
return 1;
@@ -1958,7 +433,7 @@ int mtdparts_init(void)
return 0;
}
-#endif /* #ifdef CONFIG_JFFS2_CMDLINE */
+#endif /* #ifndef CONFIG_CMD_MTDPARTS */
/**
* Return pointer to the partition of a requested number from a requested
@@ -2145,155 +620,6 @@ int do_jffs2_fsinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
return 1;
}
-/* command line only */
-#ifdef CONFIG_JFFS2_CMDLINE
-/**
- * Routine implementing u-boot chpart command. Sets new current partition based
- * on the user supplied partition id. For partition id format see find_dev_and_part().
- *
- * @param cmdtp command internal data
- * @param flag command flag
- * @param argc number of arguments supplied to the command
- * @param argv arguments list
- * @return 0 on success, 1 otherwise
- */
-int do_jffs2_chpart(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
-{
-/* command line only */
- struct mtd_device *dev;
- struct part_info *part;
- u8 pnum;
-
- if (mtdparts_init() !=0)
- return 1;
-
- if (argc < 2) {
- printf("no partition id specified\n");
- return 1;
- }
-
- if (find_dev_and_part(argv[1], &dev, &pnum, &part) != 0)
- return 1;
-
- current_dev = dev;
- current_partnum = pnum;
- current_save();
-
- printf("partition changed to %s%d,%d\n",
- MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum);
-
- return 0;
-}
-
-/**
- * Routine implementing u-boot mtdparts command. Initialize/update default global
- * partition list and process user partition request (list, add, del).
- *
- * @param cmdtp command internal data
- * @param flag command flag
- * @param argc number of arguments supplied to the command
- * @param argv arguments list
- * @return 0 on success, 1 otherwise
- */
-int do_jffs2_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
-{
- if (argc == 2) {
- if (strcmp(argv[1], "default") == 0) {
- setenv("mtdids", (char *)mtdids_default);
- setenv("mtdparts", (char *)mtdparts_default);
- setenv("partition", NULL);
-
- mtdparts_init();
- return 0;
- } else if (strcmp(argv[1], "delall") == 0) {
- /* this may be the first run, initialize lists if needed */
- mtdparts_init();
-
- setenv("mtdparts", NULL);
-
- /* jffs2_devices_init() calls current_save() */
- return jffs2_devices_init();
- }
- }
-
- /* make sure we are in sync with env variables */
- if (mtdparts_init() != 0)
- return 1;
-
- if (argc == 1) {
- list_partitions();
- return 0;
- }
-
- /* mtdparts add <mtd-dev> <size>[@<offset>] <name> [ro] */
- if (((argc == 5) || (argc == 6)) && (strcmp(argv[1], "add") == 0)) {
-#define PART_ADD_DESC_MAXLEN 64
- char tmpbuf[PART_ADD_DESC_MAXLEN];
- u8 type, num, len;
- struct mtd_device *dev;
- struct mtd_device *dev_tmp;
- struct mtdids *id;
- struct part_info *p;
-
- if (id_parse(argv[2], NULL, &type, &num) != 0)
- return 1;
-
- if ((id = id_find(type, num)) == NULL) {
- printf("no such device %s defined in mtdids variable\n", argv[2]);
- return 1;
- }
-
- len = strlen(id->mtd_id) + 1; /* 'mtd_id:' */
- len += strlen(argv[3]); /* size@offset */
- len += strlen(argv[4]) + 2; /* '(' name ')' */
- if (argv[5] && (strlen(argv[5]) == 2))
- len += 2; /* 'ro' */
-
- if (len >= PART_ADD_DESC_MAXLEN) {
- printf("too long partition description\n");
- return 1;
- }
- sprintf(tmpbuf, "%s:%s(%s)%s",
- id->mtd_id, argv[3], argv[4], argv[5] ? argv[5] : "");
- DEBUGF("add tmpbuf: %s\n", tmpbuf);
-
- if ((device_parse(tmpbuf, NULL, &dev) != 0) || (!dev))
- return 1;
-
- DEBUGF("+ %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type),
- dev->id->num, dev->id->mtd_id);
-
- if ((dev_tmp = device_find(dev->id->type, dev->id->num)) == NULL) {
- device_add(dev);
- } else {
- /* merge new partition with existing ones*/
- p = list_entry(dev->parts.next, struct part_info, link);
- if (part_add(dev_tmp, p) != 0) {
- device_del(dev);
- return 1;
- }
- }
-
- if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) {
- printf("generated mtdparts too long, reseting to null\n");
- return 1;
- }
-
- return 0;
- }
-
- /* mtdparts del part-id */
- if ((argc == 3) && (strcmp(argv[1], "del") == 0)) {
- DEBUGF("del: part-id = %s\n", argv[2]);
-
- return delete_partition(argv[2]);
- }
-
- cmd_usage(cmdtp);
- return 1;
-}
-#endif /* #ifdef CONFIG_JFFS2_CMDLINE */
-
/***************************************************/
U_BOOT_CMD(
fsload, 3, 0, do_jffs2_fsload,
@@ -2314,49 +640,4 @@ U_BOOT_CMD(
"print information about filesystems",
" - print information about filesystems\n"
);
-
-#ifdef CONFIG_JFFS2_CMDLINE
-U_BOOT_CMD(
- chpart, 2, 0, do_jffs2_chpart,
- "change active partition",
- "part-id\n"
- " - change active partition (e.g. part-id = nand0,1)\n"
-);
-
-U_BOOT_CMD(
- mtdparts, 6, 0, do_jffs2_mtdparts,
- "define flash/nand partitions",
- "\n"
- " - list partition table\n"
- "mtdparts delall\n"
- " - delete all partitions\n"
- "mtdparts del part-id\n"
- " - delete partition (e.g. part-id = nand0,1)\n"
- "mtdparts add <mtd-dev> <size>[@<offset>] [<name>] [ro]\n"
- " - add partition\n"
- "mtdparts default\n"
- " - reset partition table to defaults\n\n"
- "-----\n\n"
- "this command uses three environment variables:\n\n"
- "'partition' - keeps current partition identifier\n\n"
- "partition := <part-id>\n"
- "<part-id> := <dev-id>,part_num\n\n"
- "'mtdids' - linux kernel mtd device id <-> u-boot device id mapping\n\n"
- "mtdids=<idmap>[,<idmap>,...]\n\n"
- "<idmap> := <dev-id>=<mtd-id>\n"
- "<dev-id> := 'nand'|'nor'|'onenand'<dev-num>\n"
- "<dev-num> := mtd device number, 0...\n"
- "<mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)\n\n"
- "'mtdparts' - partition list\n\n"
- "mtdparts=mtdparts=<mtd-def>[;<mtd-def>...]\n\n"
- "<mtd-def> := <mtd-id>:<part-def>[,<part-def>...]\n"
- "<mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)\n"
- "<part-def> := <size>[@<offset>][<name>][<ro-flag>]\n"
- "<size> := standard linux memsize OR '-' to denote all remaining space\n"
- "<offset> := partition start offset within the device\n"
- "<name> := '(' NAME ')'\n"
- "<ro-flag> := when set to 'ro' makes partition read-only (not used, passed to kernel)\n"
-);
-#endif /* #ifdef CONFIG_JFFS2_CMDLINE */
-
/***************************************************/
diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
new file mode 100644
index 0000000..c8bf2c6
--- /dev/null
+++ b/common/cmd_mtdparts.c
@@ -0,0 +1,1986 @@
+/*
+ * (C) Copyright 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2002
+ * Robert Schwebel, Pengutronix, <r.schwebel@pengutronix.de>
+ *
+ * (C) Copyright 2003
+ * Kai-Uwe Bloem, Auerswald GmbH & Co KG, <linux-development@auerswald.de>
+ *
+ * (C) Copyright 2005
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Added support for reading flash partition table from environment.
+ * Parsing routines are based on driver/mtd/cmdline.c from the linux 2.4
+ * kernel tree.
+ *
+ * $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
+ * Copyright 2002 SYSGO Real-Time Solutions GmbH
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Three environment variables are used by the parsing routines:
+ *
+ * 'partition' - keeps current partition identifier
+ *
+ * partition := <part-id>
+ * <part-id> := <dev-id>,part_num
+ *
+ *
+ * 'mtdids' - linux kernel mtd device id <-> u-boot device id mapping
+ *
+ * mtdids=<idmap>[,<idmap>,...]
+ *
+ * <idmap> := <dev-id>=<mtd-id>
+ * <dev-id> := 'nand'|'nor'|'onenand'<dev-num>
+ * <dev-num> := mtd device number, 0...
+ * <mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)
+ *
+ *
+ * 'mtdparts' - partition list
+ *
+ * mtdparts=mtdparts=<mtd-def>[;<mtd-def>...]
+ *
+ * <mtd-def> := <mtd-id>:<part-def>[,<part-def>...]
+ * <mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)
+ * <part-def> := <size>[@<offset>][<name>][<ro-flag>]
+ * <size> := standard linux memsize OR '-' to denote all remaining space
+ * <offset> := partition start offset within the device
+ * <name> := '(' NAME ')'
+ * <ro-flag> := when set to 'ro' makes partition read-only (not used, passed to kernel)
+ *
+ * Notes:
+ * - each <mtd-id> used in mtdparts must albo exist in 'mtddis' mapping
+ * - if the above variables are not set defaults for a given target are used
+ *
+ * Examples:
+ *
+ * 1 NOR Flash, with 1 single writable partition:
+ * mtdids=nor0=edb7312-nor
+ * mtdparts=mtdparts=edb7312-nor:-
+ *
+ * 1 NOR Flash with 2 partitions, 1 NAND with one
+ * mtdids=nor0=edb7312-nor,nand0=edb7312-nand
+ * mtdparts=mtdparts=edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
+ *
+ */
+
+/*
+ * JFFS2/CRAMFS support
+ */
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <jffs2/jffs2.h>
+#include <linux/list.h>
+#include <linux/ctype.h>
+#include <cramfs/cramfs_fs.h>
+
+#if defined(CONFIG_CMD_NAND)
+#ifdef CONFIG_NAND_LEGACY
+#include <linux/mtd/nand_legacy.h>
+#else /* !CONFIG_NAND_LEGACY */
+#include <linux/mtd/nand.h>
+#include <nand.h>
+#endif /* !CONFIG_NAND_LEGACY */
+#endif
+
+#if defined(CONFIG_CMD_ONENAND)
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/onenand.h>
+#include <onenand_uboot.h>
+#endif
+
+/* enable/disable debugging messages */
+#define DEBUG_MTDPARTS
+#undef DEBUG_MTDPARTS
+
+#ifdef DEBUG_MTDPARTS
+# define DEBUGF(fmt, args...) printf(fmt ,##args)
+#else
+# define DEBUGF(fmt, args...)
+#endif
+
+/* special size referring to all the remaining space in a partition */
+#define SIZE_REMAINING 0xFFFFFFFF
+
+/* special offset value, it is used when not provided by user
+ *
+ * this value is used temporarily during parsing, later such offests
+ * are recalculated */
+#define OFFSET_NOT_SPECIFIED 0xFFFFFFFF
+
+/* minimum partition size */
+#define MIN_PART_SIZE 4096
+
+/* this flag needs to be set in part_info struct mask_flags
+ * field for read-only partitions */
+#define MTD_WRITEABLE_CMD 1
+
+/* default values for mtdids and mtdparts variables */
+#if defined(MTDIDS_DEFAULT)
+static const char *const mtdids_default = MTDIDS_DEFAULT;
+#else
+#warning "MTDIDS_DEFAULT not defined!"
+static const char *const mtdids_default = NULL;
+#endif
+
+#if defined(MTDPARTS_DEFAULT)
+static const char *const mtdparts_default = MTDPARTS_DEFAULT;
+#else
+#warning "MTDPARTS_DEFAULT not defined!"
+static const char *const mtdparts_default = NULL;
+#endif
+
+/* copies of last seen 'mtdids', 'mtdparts' and 'partition' env variables */
+#define MTDIDS_MAXLEN 128
+#define MTDPARTS_MAXLEN 512
+#define PARTITION_MAXLEN 16
+static char last_ids[MTDIDS_MAXLEN];
+static char last_parts[MTDPARTS_MAXLEN];
+static char last_partition[PARTITION_MAXLEN];
+
+/* low level jffs2 cache cleaning routine */
+extern void jffs2_free_cache(struct part_info *part);
+
+/* mtdids mapping list, filled by parse_ids() */
+struct list_head mtdids;
+
+/* device/partition list, parse_cmdline() parses into here */
+struct list_head devices;
+
+/* current active device and partition number */
+static struct mtd_device *current_dev = NULL;
+static u8 current_partnum = 0;
+
+static struct part_info* mtd_part_info(struct mtd_device *dev, unsigned int part_num);
+
+/* command line only routines */
+static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_len);
+static int device_del(struct mtd_device *dev);
+
+/**
+ * Parses a string into a number. The number stored at ptr is
+ * potentially suffixed with K (for kilobytes, or 1024 bytes),
+ * M (for megabytes, or 1048576 bytes), or G (for gigabytes, or
+ * 1073741824). If the number is suffixed with K, M, or G, then
+ * the return value is the number multiplied by one kilobyte, one
+ * megabyte, or one gigabyte, respectively.
+ *
+ * @param ptr where parse begins
+ * @param retptr output pointer to next char after parse completes (output)
+ * @return resulting unsigned int
+ */
+static unsigned long memsize_parse (const char *const ptr, const char **retptr)
+{
+ unsigned long ret = simple_strtoul(ptr, (char **)retptr, 0);
+
+ switch (**retptr) {
+ case 'G':
+ case 'g':
+ ret <<= 10;
+ case 'M':
+ case 'm':
+ ret <<= 10;
+ case 'K':
+ case 'k':
+ ret <<= 10;
+ (*retptr)++;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * Format string describing supplied size. This routine does the opposite job
+ * to memsize_parse(). Size in bytes is converted to string and if possible
+ * shortened by using k (kilobytes), m (megabytes) or g (gigabytes) suffix.
+ *
+ * Note, that this routine does not check for buffer overflow, it's the caller
+ * who must assure enough space.
+ *
+ * @param buf output buffer
+ * @param size size to be converted to string
+ */
+static void memsize_format(char *buf, u32 size)
+{
+#define SIZE_GB ((u32)1024*1024*1024)
+#define SIZE_MB ((u32)1024*1024)
+#define SIZE_KB ((u32)1024)
+
+ if ((size % SIZE_GB) == 0)
+ sprintf(buf, "%ug", size/SIZE_GB);
+ else if ((size % SIZE_MB) == 0)
+ sprintf(buf, "%um", size/SIZE_MB);
+ else if (size % SIZE_KB == 0)
+ sprintf(buf, "%uk", size/SIZE_KB);
+ else
+ sprintf(buf, "%u", size);
+}
+
+/**
+ * This routine does global indexing of all partitions. Resulting index for
+ * current partition is saved in 'mtddevnum'. Current partition name in
+ * 'mtddevname'.
+ */
+static void index_partitions(void)
+{
+ char buf[16];
+ u16 mtddevnum;
+ struct part_info *part;
+ struct list_head *dentry;
+ struct mtd_device *dev;
+
+ DEBUGF("--- index partitions ---\n");
+
+ if (current_dev) {
+ mtddevnum = 0;
+ list_for_each(dentry, &devices) {
+ dev = list_entry(dentry, struct mtd_device, link);
+ if (dev == current_dev) {
+ mtddevnum += current_partnum;
+ sprintf(buf, "%d", mtddevnum);
+ setenv("mtddevnum", buf);
+ break;
+ }
+ mtddevnum += dev->num_parts;
+ }
+
+ part = mtd_part_info(current_dev, current_partnum);
+ setenv("mtddevname", part->name);
+
+ DEBUGF("=> mtddevnum %d,\n=> mtddevname %s\n", mtddevnum, part->name);
+ } else {
+ setenv("mtddevnum", NULL);
+ setenv("mtddevname", NULL);
+
+ DEBUGF("=> mtddevnum NULL\n=> mtddevname NULL\n");
+ }
+}
+
+/**
+ * Save current device and partition in environment variable 'partition'.
+ */
+static void current_save(void)
+{
+ char buf[16];
+
+ DEBUGF("--- current_save ---\n");
+
+ if (current_dev) {
+ sprintf(buf, "%s%d,%d", MTD_DEV_TYPE(current_dev->id->type),
+ current_dev->id->num, current_partnum);
+
+ setenv("partition", buf);
+ strncpy(last_partition, buf, 16);
+
+ DEBUGF("=> partition %s\n", buf);
+ } else {
+ setenv("partition", NULL);
+ last_partition[0] = '\0';
+
+ DEBUGF("=> partition NULL\n");
+ }
+ index_partitions();
+}
+
+/**
+ * Performs sanity check for supplied NOR flash partition. Table of existing
+ * NOR flash devices is searched and partition device is located. Alignment
+ * with the granularity of NOR flash sectors is verified.
+ *
+ * @param id of the parent device
+ * @param part partition to validate
+ * @return 0 if partition is valid, 1 otherwise
+ */
+static int part_validate_nor(struct mtdids *id, struct part_info *part)
+{
+#if defined(CONFIG_CMD_FLASH)
+ /* info for FLASH chips */
+ extern flash_info_t flash_info[];
+ flash_info_t *flash;
+ int offset_aligned;
+ u32 end_offset, sector_size = 0;
+ int i;
+
+ flash = &flash_info[id->num];
+
+ /* size of last sector */
+ part->sector_size = flash->size -
+ (flash->start[flash->sector_count-1] - flash->start[0]);
+
+ offset_aligned = 0;
+ for (i = 0; i < flash->sector_count; i++) {
+ if ((flash->start[i] - flash->start[0]) == part->offset) {
+ offset_aligned = 1;
+ break;
+ }
+ }
+ if (offset_aligned == 0) {
+ printf("%s%d: partition (%s) start offset alignment incorrect\n",
+ MTD_DEV_TYPE(id->type), id->num, part->name);
+ return 1;
+ }
+
+ end_offset = part->offset + part->size;
+ offset_aligned = 0;
+ for (i = 0; i < flash->sector_count; i++) {
+ if (i) {
+ sector_size = flash->start[i] - flash->start[i-1];
+ if (part->sector_size < sector_size)
+ part->sector_size = sector_size;
+ }
+ if ((flash->start[i] - flash->start[0]) == end_offset)
+ offset_aligned = 1;
+ }
+
+ if (offset_aligned || flash->size == end_offset)
+ return 0;
+
+ printf("%s%d: partition (%s) size alignment incorrect\n",
+ MTD_DEV_TYPE(id->type), id->num, part->name);
+#endif
+ return 1;
+}
+
+/**
+ * Performs sanity check for supplied NAND flash partition. Table of existing
+ * NAND flash devices is searched and partition device is located. Alignment
+ * with the granularity of nand erasesize is verified.
+ *
+ * @param id of the parent device
+ * @param part partition to validate
+ * @return 0 if partition is valid, 1 otherwise
+ */
+static int part_validate_nand(struct mtdids *id, struct part_info *part)
+{
+#if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND)
+ /* info for NAND chips */
+ nand_info_t *nand;
+
+ nand = &nand_info[id->num];
+
+ part->sector_size = nand->erasesize;
+
+ if ((unsigned long)(part->offset) % nand->erasesize) {
+ printf("%s%d: partition (%s) start offset alignment incorrect\n",
+ MTD_DEV_TYPE(id->type), id->num, part->name);
+ return 1;
+ }
+
+ if (part->size % nand->erasesize) {
+ printf("%s%d: partition (%s) size alignment incorrect\n",
+ MTD_DEV_TYPE(id->type), id->num, part->name);
+ return 1;
+ }
+
+ return 0;
+#else
+ return 1;
+#endif
+}
+
+/**
+ * Performs sanity check for supplied OneNAND flash partition.
+ * Table of existing OneNAND flash devices is searched and partition device
+ * is located. Alignment with the granularity of nand erasesize is verified.
+ *
+ * @param id of the parent device
+ * @param part partition to validate
+ * @return 0 if partition is valid, 1 otherwise
+ */
+static int part_validate_onenand(struct mtdids *id, struct part_info *part)
+{
+#if defined(CONFIG_CMD_ONENAND)
+ /* info for OneNAND chips */
+ struct mtd_info *mtd;
+
+ mtd = &onenand_mtd;
+
+ part->sector_size = mtd->erasesize;
+
+ if ((unsigned long)(part->offset) % mtd->erasesize) {
+ printf("%s%d: partition (%s) start offset"
+ "alignment incorrect\n",
+ MTD_DEV_TYPE(id->type), id->num, part->name);
+ return 1;
+ }
+
+ if (part->size % mtd->erasesize) {
+ printf("%s%d: partition (%s) size alignment incorrect\n",
+ MTD_DEV_TYPE(id->type), id->num, part->name);
+ return 1;
+ }
+
+ return 0;
+#else
+ return 1;
+#endif
+}
+
+
+/**
+ * Performs sanity check for supplied partition. Offset and size are verified
+ * to be within valid range. Partition type is checked and either
+ * parts_validate_nor() or parts_validate_nand() is called with the argument
+ * of part.
+ *
+ * @param id of the parent device
+ * @param part partition to validate
+ * @return 0 if partition is valid, 1 otherwise
+ */
+static int part_validate(struct mtdids *id, struct part_info *part)
+{
+ if (part->size == SIZE_REMAINING)
+ part->size = id->size - part->offset;
+
+ if (part->offset > id->size) {
+ printf("%s: offset %08x beyond flash size %08x\n",
+ id->mtd_id, part->offset, id->size);
+ return 1;
+ }
+
+ if ((part->offset + part->size) <= part->offset) {
+ printf("%s%d: partition (%s) size too big\n",
+ MTD_DEV_TYPE(id->type), id->num, part->name);
+ return 1;
+ }
+
+ if (part->offset + part->size > id->size) {
+ printf("%s: partitioning exceeds flash size\n", id->mtd_id);
+ return 1;
+ }
+
+ if (id->type == MTD_DEV_TYPE_NAND)
+ return part_validate_nand(id, part);
+ else if (id->type == MTD_DEV_TYPE_NOR)
+ return part_validate_nor(id, part);
+ else if (id->type == MTD_DEV_TYPE_ONENAND)
+ return part_validate_onenand(id, part);
+ else
+ DEBUGF("part_validate: invalid dev type\n");
+
+ return 1;
+}
+
+/**
+ * Delete selected partition from the partion list of the specified device.
+ *
+ * @param dev device to delete partition from
+ * @param part partition to delete
+ * @return 0 on success, 1 otherwise
+ */
+static int part_del(struct mtd_device *dev, struct part_info *part)
+{
+ u8 current_save_needed = 0;
+
+ /* if there is only one partition, remove whole device */
+ if (dev->num_parts == 1)
+ return device_del(dev);
+
+ /* otherwise just delete this partition */
+
+ if (dev == current_dev) {
+ /* we are modyfing partitions for the current device,
+ * update current */
+ struct part_info *curr_pi;
+ curr_pi = mtd_part_info(current_dev, current_partnum);
+
+ if (curr_pi) {
+ if (curr_pi == part) {
+ printf("current partition deleted, resetting current to 0\n");
+ current_partnum = 0;
+ } else if (part->offset <= curr_pi->offset) {
+ current_partnum--;
+ }
+ current_save_needed = 1;
+ }
+ }
+
+#ifdef CONFIG_NAND_LEGACY
+ jffs2_free_cache(part);
+#endif
+ list_del(&part->link);
+ free(part);
+ dev->num_parts--;
+
+ if (current_save_needed > 0)
+ current_save();
+ else
+ index_partitions();
+
+ return 0;
+}
+
+/**
+ * Delete all partitions from parts head list, free memory.
+ *
+ * @param head list of partitions to delete
+ */
+static void part_delall(struct list_head *head)
+{
+ struct list_head *entry, *n;
+ struct part_info *part_tmp;
+
+ /* clean tmp_list and free allocated memory */
+ list_for_each_safe(entry, n, head) {
+ part_tmp = list_entry(entry, struct part_info, link);
+
+#ifdef CONFIG_NAND_LEGACY
+ jffs2_free_cache(part_tmp);
+#endif
+ list_del(entry);
+ free(part_tmp);
+ }
+}
+
+/**
+ * Add new partition to the supplied partition list. Make sure partitions are
+ * sorted by offset in ascending order.
+ *
+ * @param head list this partition is to be added to
+ * @param new partition to be added
+ */
+static int part_sort_add(struct mtd_device *dev, struct part_info *part)
+{
+ struct list_head *entry;
+ struct part_info *new_pi, *curr_pi;
+
+ /* link partition to parrent dev */
+ part->dev = dev;
+
+ if (list_empty(&dev->parts)) {
+ DEBUGF("part_sort_add: list empty\n");
+ list_add(&part->link, &dev->parts);
+ dev->num_parts++;
+ index_partitions();
+ return 0;
+ }
+
+ new_pi = list_entry(&part->link, struct part_info, link);
+
+ /* get current partition info if we are updating current device */
+ curr_pi = NULL;
+ if (dev == current_dev)
+ curr_pi = mtd_part_info(current_dev, current_partnum);
+
+ list_for_each(entry, &dev->parts) {
+ struct part_info *pi;
+
+ pi = list_entry(entry, struct part_info, link);
+
+ /* be compliant with kernel cmdline, allow only one partition at offset zero */
+ if ((new_pi->offset == pi->offset) && (pi->offset == 0)) {
+ printf("cannot add second partition at offset 0\n");
+ return 1;
+ }
+
+ if (new_pi->offset <= pi->offset) {
+ list_add_tail(&part->link, entry);
+ dev->num_parts++;
+
+ if (curr_pi && (pi->offset <= curr_pi->offset)) {
+ /* we are modyfing partitions for the current
+ * device, update current */
+ current_partnum++;
+ current_save();
+ } else {
+ index_partitions();
+ }
+ return 0;
+ }
+ }
+
+ list_add_tail(&part->link, &dev->parts);
+ dev->num_parts++;
+ index_partitions();
+ return 0;
+}
+
+/**
+ * Add provided partition to the partition list of a given device.
+ *
+ * @param dev device to which partition is added
+ * @param part partition to be added
+ * @return 0 on success, 1 otherwise
+ */
+static int part_add(struct mtd_device *dev, struct part_info *part)
+{
+ /* verify alignment and size */
+ if (part_validate(dev->id, part) != 0)
+ return 1;
+
+ /* partition is ok, add it to the list */
+ if (part_sort_add(dev, part) != 0)
+ return 1;
+
+ return 0;
+}
+
+/**
+ * Parse one partition definition, allocate memory and return pointer to this
+ * location in retpart.
+ *
+ * @param partdef pointer to the partition definition string i.e. <part-def>
+ * @param ret output pointer to next char after parse completes (output)
+ * @param retpart pointer to the allocated partition (output)
+ * @return 0 on success, 1 otherwise
+ */
+static int part_parse(const char *const partdef, const char **ret, struct part_info **retpart)
+{
+ struct part_info *part;
+ unsigned long size;
+ unsigned long offset;
+ const char *name;
+ int name_len;
+ unsigned int mask_flags;
+ const char *p;
+
+ p = partdef;
+ *retpart = NULL;
+ *ret = NULL;
+
+ /* fetch the partition size */
+ if (*p == '-') {
+ /* assign all remaining space to this partition */
+ DEBUGF("'-': remaining size assigned\n");
+ size = SIZE_REMAINING;
+ p++;
+ } else {
+ size = memsize_parse(p, &p);
+ if (size < MIN_PART_SIZE) {
+ printf("partition size too small (%lx)\n", size);
+ return 1;
+ }
+ }
+
+ /* check for offset */
+ offset = OFFSET_NOT_SPECIFIED;
+ if (*p == '@') {
+ p++;
+ offset = memsize_parse(p, &p);
+ }
+
+ /* now look for the name */
+ if (*p == '(') {
+ name = ++p;
+ if ((p = strchr(name, ')')) == NULL) {
+ printf("no closing ) found in partition name\n");
+ return 1;
+ }
+ name_len = p - name + 1;
+ if ((name_len - 1) == 0) {
+ printf("empty partition name\n");
+ return 1;
+ }
+ p++;
+ } else {
+ /* 0x00000000@0x00000000 */
+ name_len = 22;
+ name = NULL;
+ }
+
+ /* test for options */
+ mask_flags = 0;
+ if (strncmp(p, "ro", 2) == 0) {
+ mask_flags |= MTD_WRITEABLE_CMD;
+ p += 2;
+ }
+
+ /* check for next partition definition */
+ if (*p == ',') {
+ if (size == SIZE_REMAINING) {
+ *ret = NULL;
+ printf("no partitions allowed after a fill-up partition\n");
+ return 1;
+ }
+ *ret = ++p;
+ } else if ((*p == ';') || (*p == '\0')) {
+ *ret = p;
+ } else {
+ printf("unexpected character '%c' at the end of partition\n", *p);
+ *ret = NULL;
+ return 1;
+ }
+
+ /* allocate memory */
+ part = (struct part_info *)malloc(sizeof(struct part_info) + name_len);
+ if (!part) {
+ printf("out of memory\n");
+ return 1;
+ }
+ memset(part, 0, sizeof(struct part_info) + name_len);
+ part->size = size;
+ part->offset = offset;
+ part->mask_flags = mask_flags;
+ part->name = (char *)(part + 1);
+
+ if (name) {
+ /* copy user provided name */
+ strncpy(part->name, name, name_len - 1);
+ part->auto_name = 0;
+ } else {
+ /* auto generated name in form of size@offset */
+ sprintf(part->name, "0x%08lx@0x%08lx", size, offset);
+ part->auto_name = 1;
+ }
+
+ part->name[name_len - 1] = '\0';
+ INIT_LIST_HEAD(&part->link);
+
+ DEBUGF("+ partition: name %-22s size 0x%08x offset 0x%08x mask flags %d\n",
+ part->name, part->size,
+ part->offset, part->mask_flags);
+
+ *retpart = part;
+ return 0;
+}
+
+/**
+ * Check device number to be within valid range for given device type.
+ *
+ * @param dev device to validate
+ * @return 0 if device is valid, 1 otherwise
+ */
+int mtd_device_validate(u8 type, u8 num, u32 *size)
+{
+ if (type == MTD_DEV_TYPE_NOR) {
+#if defined(CONFIG_CMD_FLASH)
+ if (num < CONFIG_SYS_MAX_FLASH_BANKS) {
+ extern flash_info_t flash_info[];
+ *size = flash_info[num].size;
+
+ return 0;
+ }
+
+ printf("no such FLASH device: %s%d (valid range 0 ... %d\n",
+ MTD_DEV_TYPE(type), num, CONFIG_SYS_MAX_FLASH_BANKS - 1);
+#else
+ printf("support for FLASH devices not present\n");
+#endif
+ } else if (type == MTD_DEV_TYPE_NAND) {
+#if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND)
+ if (num < CONFIG_SYS_MAX_NAND_DEVICE) {
+#ifndef CONFIG_NAND_LEGACY
+ *size = nand_info[num].size;
+#else
+ extern struct nand_chip nand_dev_desc[CONFIG_SYS_MAX_NAND_DEVICE];
+ *size = nand_dev_desc[num].totlen;
+#endif
+ return 0;
+ }
+
+ printf("no such NAND device: %s%d (valid range 0 ... %d)\n",
+ MTD_DEV_TYPE(type), num, CONFIG_SYS_MAX_NAND_DEVICE - 1);
+#else
+ printf("support for NAND devices not present\n");
+#endif
+ } else if (type == MTD_DEV_TYPE_ONENAND) {
+#if defined(CONFIG_CMD_ONENAND)
+ *size = onenand_mtd.size;
+ return 0;
+#else
+ printf("support for OneNAND devices not present\n");
+#endif
+ } else
+ printf("Unknown defice type %d\n", type);
+
+ return 1;
+}
+
+/**
+ * Delete all mtd devices from a supplied devices list, free memory allocated for
+ * each device and delete all device partitions.
+ *
+ * @return 0 on success, 1 otherwise
+ */
+static int device_delall(struct list_head *head)
+{
+ struct list_head *entry, *n;
+ struct mtd_device *dev_tmp;
+
+ /* clean devices list */
+ list_for_each_safe(entry, n, head) {
+ dev_tmp = list_entry(entry, struct mtd_device, link);
+ list_del(entry);
+ part_delall(&dev_tmp->parts);
+ free(dev_tmp);
+ }
+ INIT_LIST_HEAD(&devices);
+
+ return 0;
+}
+
+/**
+ * If provided device exists it's partitions are deleted, device is removed
+ * from device list and device memory is freed.
+ *
+ * @param dev device to be deleted
+ * @return 0 on success, 1 otherwise
+ */
+static int device_del(struct mtd_device *dev)
+{
+ part_delall(&dev->parts);
+ list_del(&dev->link);
+ free(dev);
+
+ if (dev == current_dev) {
+ /* we just deleted current device */
+ if (list_empty(&devices)) {
+ current_dev = NULL;
+ } else {
+ /* reset first partition from first dev from the
+ * devices list as current */
+ current_dev = list_entry(devices.next, struct mtd_device, link);
+ current_partnum = 0;
+ }
+ current_save();
+ return 0;
+ }
+
+ index_partitions();
+ return 0;
+}
+
+/**
+ * Search global device list and return pointer to the device of type and num
+ * specified.
+ *
+ * @param type device type
+ * @param num device number
+ * @return NULL if requested device does not exist
+ */
+static struct mtd_device* device_find(u8 type, u8 num)
+{
+ struct list_head *entry;
+ struct mtd_device *dev_tmp;
+
+ list_for_each(entry, &devices) {
+ dev_tmp = list_entry(entry, struct mtd_device, link);
+
+ if ((dev_tmp->id->type == type) && (dev_tmp->id->num == num))
+ return dev_tmp;
+ }
+
+ return NULL;
+}
+
+/**
+ * Add specified device to the global device list.
+ *
+ * @param dev device to be added
+ */
+static void device_add(struct mtd_device *dev)
+{
+ u8 current_save_needed = 0;
+
+ if (list_empty(&devices)) {
+ current_dev = dev;
+ current_partnum = 0;
+ current_save_needed = 1;
+ }
+
+ list_add_tail(&dev->link, &devices);
+
+ if (current_save_needed > 0)
+ current_save();
+ else
+ index_partitions();
+}
+
+/**
+ * Parse device type, name and mtd-id. If syntax is ok allocate memory and
+ * return pointer to the device structure.
+ *
+ * @param mtd_dev pointer to the device definition string i.e. <mtd-dev>
+ * @param ret output pointer to next char after parse completes (output)
+ * @param retdev pointer to the allocated device (output)
+ * @return 0 on success, 1 otherwise
+ */
+static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_device **retdev)
+{
+ struct mtd_device *dev;
+ struct part_info *part;
+ struct mtdids *id;
+ const char *mtd_id;
+ unsigned int mtd_id_len;
+ const char *p, *pend;
+ LIST_HEAD(tmp_list);
+ struct list_head *entry, *n;
+ u16 num_parts;
+ u32 offset;
+ int err = 1;
+
+ p = mtd_dev;
+ *retdev = NULL;
+ *ret = NULL;
+
+ DEBUGF("===device_parse===\n");
+
+ /* fetch <mtd-id> */
+ mtd_id = p;
+ if (!(p = strchr(mtd_id, ':'))) {
+ printf("no <mtd-id> identifier\n");
+ return 1;
+ }
+ mtd_id_len = p - mtd_id + 1;
+ p++;
+
+ /* verify if we have a valid device specified */
+ if ((id = id_find_by_mtd_id(mtd_id, mtd_id_len - 1)) == NULL) {
+ printf("invalid mtd device '%.*s'\n", mtd_id_len - 1, mtd_id);
+ return 1;
+ }
+
+ DEBUGF("dev type = %d (%s), dev num = %d, mtd-id = %s\n",
+ id->type, MTD_DEV_TYPE(id->type),
+ id->num, id->mtd_id);
+ pend = strchr(p, ';');
+ DEBUGF("parsing partitions %.*s\n", (pend ? pend - p : strlen(p)), p);
+
+
+ /* parse partitions */
+ num_parts = 0;
+
+ offset = 0;
+ if ((dev = device_find(id->type, id->num)) != NULL) {
+ /* if device already exists start at the end of the last partition */
+ part = list_entry(dev->parts.prev, struct part_info, link);
+ offset = part->offset + part->size;
+ }
+
+ while (p && (*p != '\0') && (*p != ';')) {
+ err = 1;
+ if ((part_parse(p, &p, &part) != 0) || (!part))
+ break;
+
+ /* calculate offset when not specified */
+ if (part->offset == OFFSET_NOT_SPECIFIED)
+ part->offset = offset;
+ else
+ offset = part->offset;
+
+ /* verify alignment and size */
+ if (part_validate(id, part) != 0)
+ break;
+
+ offset += part->size;
+
+ /* partition is ok, add it to the list */
+ list_add_tail(&part->link, &tmp_list);
+ num_parts++;
+ err = 0;
+ }
+ if (err == 1) {
+ part_delall(&tmp_list);
+ return 1;
+ }
+
+ if (num_parts == 0) {
+ printf("no partitions for device %s%d (%s)\n",
+ MTD_DEV_TYPE(id->type), id->num, id->mtd_id);
+ return 1;
+ }
+
+ DEBUGF("\ntotal partitions: %d\n", num_parts);
+
+ /* check for next device presence */
+ if (p) {
+ if (*p == ';') {
+ *ret = ++p;
+ } else if (*p == '\0') {
+ *ret = p;
+ } else {
+ printf("unexpected character '%c' at the end of device\n", *p);
+ *ret = NULL;
+ return 1;
+ }
+ }
+
+ /* allocate memory for mtd_device structure */
+ if ((dev = (struct mtd_device *)malloc(sizeof(struct mtd_device))) == NULL) {
+ printf("out of memory\n");
+ return 1;
+ }
+ memset(dev, 0, sizeof(struct mtd_device));
+ dev->id = id;
+ dev->num_parts = 0; /* part_sort_add increments num_parts */
+ INIT_LIST_HEAD(&dev->parts);
+ INIT_LIST_HEAD(&dev->link);
+
+ /* move partitions from tmp_list to dev->parts */
+ list_for_each_safe(entry, n, &tmp_list) {
+ part = list_entry(entry, struct part_info, link);
+ list_del(entry);
+ if (part_sort_add(dev, part) != 0) {
+ device_del(dev);
+ return 1;
+ }
+ }
+
+ *retdev = dev;
+
+ DEBUGF("===\n\n");
+ return 0;
+}
+
+/**
+ * Initialize global device list.
+ *
+ * @return 0 on success, 1 otherwise
+ */
+static int mtd_devices_init(void)
+{
+ last_parts[0] = '\0';
+ current_dev = NULL;
+ current_save();
+
+ return device_delall(&devices);
+}
+
+/*
+ * Search global mtdids list and find id of requested type and number.
+ *
+ * @return pointer to the id if it exists, NULL otherwise
+ */
+static struct mtdids* id_find(u8 type, u8 num)
+{
+ struct list_head *entry;
+ struct mtdids *id;
+
+ list_for_each(entry, &mtdids) {
+ id = list_entry(entry, struct mtdids, link);
+
+ if ((id->type == type) && (id->num == num))
+ return id;
+ }
+
+ return NULL;
+}
+
+/**
+ * Search global mtdids list and find id of a requested mtd_id.
+ *
+ * Note: first argument is not null terminated.
+ *
+ * @param mtd_id string containing requested mtd_id
+ * @param mtd_id_len length of supplied mtd_id
+ * @return pointer to the id if it exists, NULL otherwise
+ */
+static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_len)
+{
+ struct list_head *entry;
+ struct mtdids *id;
+
+ DEBUGF("--- id_find_by_mtd_id: '%.*s' (len = %d)\n",
+ mtd_id_len, mtd_id, mtd_id_len);
+
+ list_for_each(entry, &mtdids) {
+ id = list_entry(entry, struct mtdids, link);
+
+ DEBUGF("entry: '%s' (len = %d)\n",
+ id->mtd_id, strlen(id->mtd_id));
+
+ if (mtd_id_len != strlen(id->mtd_id))
+ continue;
+ if (strncmp(id->mtd_id, mtd_id, mtd_id_len) == 0)
+ return id;
+ }
+
+ return NULL;
+}
+
+/**
+ * Parse device id string <dev-id> := 'nand'|'nor'|'onenand'<dev-num>,
+ * return device type and number.
+ *
+ * @param id string describing device id
+ * @param ret_id output pointer to next char after parse completes (output)
+ * @param dev_type parsed device type (output)
+ * @param dev_num parsed device number (output)
+ * @return 0 on success, 1 otherwise
+ */
+int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num)
+{
+ const char *p = id;
+
+ *dev_type = 0;
+ if (strncmp(p, "nand", 4) == 0) {
+ *dev_type = MTD_DEV_TYPE_NAND;
+ p += 4;
+ } else if (strncmp(p, "nor", 3) == 0) {
+ *dev_type = MTD_DEV_TYPE_NOR;
+ p += 3;
+ } else if (strncmp(p, "onenand", 7) == 0) {
+ *dev_type = MTD_DEV_TYPE_ONENAND;
+ p += 7;
+ } else {
+ printf("incorrect device type in %s\n", id);
+ return 1;
+ }
+
+ if (!isdigit(*p)) {
+ printf("incorrect device number in %s\n", id);
+ return 1;
+ }
+
+ *dev_num = simple_strtoul(p, (char **)&p, 0);
+ if (ret_id)
+ *ret_id = p;
+ return 0;
+}
+
+/**
+ * Process all devices and generate corresponding mtdparts string describing
+ * all partitions on all devices.
+ *
+ * @param buf output buffer holding generated mtdparts string (output)
+ * @param buflen buffer size
+ * @return 0 on success, 1 otherwise
+ */
+static int generate_mtdparts(char *buf, u32 buflen)
+{
+ struct list_head *pentry, *dentry;
+ struct mtd_device *dev;
+ struct part_info *part, *prev_part;
+ char *p = buf;
+ char tmpbuf[32];
+ u32 size, offset, len, part_cnt;
+ u32 maxlen = buflen - 1;
+
+ DEBUGF("--- generate_mtdparts ---\n");
+
+ if (list_empty(&devices)) {
+ buf[0] = '\0';
+ return 0;
+ }
+
+ sprintf(p, "mtdparts=");
+ p += 9;
+
+ list_for_each(dentry, &devices) {
+ dev = list_entry(dentry, struct mtd_device, link);
+
+ /* copy mtd_id */
+ len = strlen(dev->id->mtd_id) + 1;
+ if (len > maxlen)
+ goto cleanup;
+ memcpy(p, dev->id->mtd_id, len - 1);
+ p += len - 1;
+ *(p++) = ':';
+ maxlen -= len;
+
+ /* format partitions */
+ prev_part = NULL;
+ part_cnt = 0;
+ list_for_each(pentry, &dev->parts) {
+ part = list_entry(pentry, struct part_info, link);
+ size = part->size;
+ offset = part->offset;
+ part_cnt++;
+
+ /* partition size */
+ memsize_format(tmpbuf, size);
+ len = strlen(tmpbuf);
+ if (len > maxlen)
+ goto cleanup;
+ memcpy(p, tmpbuf, len);
+ p += len;
+ maxlen -= len;
+
+
+ /* add offset only when there is a gap between
+ * partitions */
+ if ((!prev_part && (offset != 0)) ||
+ (prev_part && ((prev_part->offset + prev_part->size) != part->offset))) {
+
+ memsize_format(tmpbuf, offset);
+ len = strlen(tmpbuf) + 1;
+ if (len > maxlen)
+ goto cleanup;
+ *(p++) = '@';
+ memcpy(p, tmpbuf, len - 1);
+ p += len - 1;
+ maxlen -= len;
+ }
+
+ /* copy name only if user supplied */
+ if(!part->auto_name) {
+ len = strlen(part->name) + 2;
+ if (len > maxlen)
+ goto cleanup;
+
+ *(p++) = '(';
+ memcpy(p, part->name, len - 2);
+ p += len - 2;
+ *(p++) = ')';
+ maxlen -= len;
+ }
+
+ /* ro mask flag */
+ if (part->mask_flags && MTD_WRITEABLE_CMD) {
+ len = 2;
+ if (len > maxlen)
+ goto cleanup;
+ *(p++) = 'r';
+ *(p++) = 'o';
+ maxlen -= 2;
+ }
+
+ /* print ',' separator if there are other partitions
+ * following */
+ if (dev->num_parts > part_cnt) {
+ if (1 > maxlen)
+ goto cleanup;
+ *(p++) = ',';
+ maxlen--;
+ }
+ prev_part = part;
+ }
+ /* print ';' separator if there are other devices following */
+ if (dentry->next != &devices) {
+ if (1 > maxlen)
+ goto cleanup;
+ *(p++) = ';';
+ maxlen--;
+ }
+ }
+
+ /* we still have at least one char left, as we decremented maxlen at
+ * the begining */
+ *p = '\0';
+
+ return 0;
+
+cleanup:
+ last_parts[0] = '\0';
+ return 1;
+}
+
+/**
+ * Call generate_mtdparts to process all devices and generate corresponding
+ * mtdparts string, save it in mtdparts environment variable.
+ *
+ * @param buf output buffer holding generated mtdparts string (output)
+ * @param buflen buffer size
+ * @return 0 on success, 1 otherwise
+ */
+static int generate_mtdparts_save(char *buf, u32 buflen)
+{
+ int ret;
+
+ ret = generate_mtdparts(buf, buflen);
+
+ if ((buf[0] != '\0') && (ret == 0))
+ setenv("mtdparts", buf);
+ else
+ setenv("mtdparts", NULL);
+
+ return ret;
+}
+
+/**
+ * Format and print out a partition list for each device from global device
+ * list.
+ */
+static void list_partitions(void)
+{
+ struct list_head *dentry, *pentry;
+ struct part_info *part;
+ struct mtd_device *dev;
+ int part_num;
+
+ DEBUGF("\n---list_partitions---\n");
+ list_for_each(dentry, &devices) {
+ dev = list_entry(dentry, struct mtd_device, link);
+ printf("\ndevice %s%d <%s>, # parts = %d\n",
+ MTD_DEV_TYPE(dev->id->type), dev->id->num,
+ dev->id->mtd_id, dev->num_parts);
+ printf(" #: name\t\t\tsize\t\toffset\t\tmask_flags\n");
+
+ /* list partitions for given device */
+ part_num = 0;
+ list_for_each(pentry, &dev->parts) {
+ part = list_entry(pentry, struct part_info, link);
+ printf("%2d: %-20s0x%08x\t0x%08x\t%d\n",
+ part_num, part->name, part->size,
+ part->offset, part->mask_flags);
+
+ part_num++;
+ }
+ }
+ if (list_empty(&devices))
+ printf("no partitions defined\n");
+
+ /* current_dev is not NULL only when we have non empty device list */
+ if (current_dev) {
+ part = mtd_part_info(current_dev, current_partnum);
+ if (part) {
+ printf("\nactive partition: %s%d,%d - (%s) 0x%08x @ 0x%08x\n",
+ MTD_DEV_TYPE(current_dev->id->type),
+ current_dev->id->num, current_partnum,
+ part->name, part->size, part->offset);
+ } else {
+ printf("could not get current partition info\n\n");
+ }
+ }
+
+ printf("\ndefaults:\n");
+ printf("mtdids : %s\n", mtdids_default);
+ printf("mtdparts: %s\n", mtdparts_default);
+}
+
+/**
+ * Given partition identifier in form of <dev_type><dev_num>,<part_num> find
+ * corresponding device and verify partition number.
+ *
+ * @param id string describing device and partition or partition name
+ * @param dev pointer to the requested device (output)
+ * @param part_num verified partition number (output)
+ * @param part pointer to requested partition (output)
+ * @return 0 on success, 1 otherwise
+ */
+int find_dev_and_part(const char *id, struct mtd_device **dev,
+ u8 *part_num, struct part_info **part)
+{
+ struct list_head *dentry, *pentry;
+ u8 type, dnum, pnum;
+ const char *p;
+
+ DEBUGF("--- find_dev_and_part ---\nid = %s\n", id);
+
+ list_for_each(dentry, &devices) {
+ *part_num = 0;
+ *dev = list_entry(dentry, struct mtd_device, link);
+ list_for_each(pentry, &(*dev)->parts) {
+ *part = list_entry(pentry, struct part_info, link);
+ if (strcmp((*part)->name, id) == 0)
+ return 0;
+ (*part_num)++;
+ }
+ }
+
+ p = id;
+ *dev = NULL;
+ *part = NULL;
+ *part_num = 0;
+
+ if (mtd_id_parse(p, &p, &type, &dnum) != 0)
+ return 1;
+
+ if ((*p++ != ',') || (*p == '\0')) {
+ printf("no partition number specified\n");
+ return 1;
+ }
+ pnum = simple_strtoul(p, (char **)&p, 0);
+ if (*p != '\0') {
+ printf("unexpected trailing character '%c'\n", *p);
+ return 1;
+ }
+
+ if ((*dev = device_find(type, dnum)) == NULL) {
+ printf("no such device %s%d\n", MTD_DEV_TYPE(type), dnum);
+ return 1;
+ }
+
+ if ((*part = mtd_part_info(*dev, pnum)) == NULL) {
+ printf("no such partition\n");
+ *dev = NULL;
+ return 1;
+ }
+
+ *part_num = pnum;
+
+ return 0;
+}
+
+/**
+ * Find and delete partition. For partition id format see find_dev_and_part().
+ *
+ * @param id string describing device and partition
+ * @return 0 on success, 1 otherwise
+ */
+static int delete_partition(const char *id)
+{
+ u8 pnum;
+ struct mtd_device *dev;
+ struct part_info *part;
+
+ if (find_dev_and_part(id, &dev, &pnum, &part) == 0) {
+
+ DEBUGF("delete_partition: device = %s%d, partition %d = (%s) 0x%08lx@0x%08lx\n",
+ MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum,
+ part->name, part->size, part->offset);
+
+ if (part_del(dev, part) != 0)
+ return 1;
+
+ if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) {
+ printf("generated mtdparts too long, reseting to null\n");
+ return 1;
+ }
+ return 0;
+ }
+
+ printf("partition %s not found\n", id);
+ return 1;
+}
+
+/**
+ * Accept character string describing mtd partitions and call device_parse()
+ * for each entry. Add created devices to the global devices list.
+ *
+ * @param mtdparts string specifing mtd partitions
+ * @return 0 on success, 1 otherwise
+ */
+static int parse_mtdparts(const char *const mtdparts)
+{
+ const char *p = mtdparts;
+ struct mtd_device *dev;
+ int err = 1;
+
+ DEBUGF("\n---parse_mtdparts---\nmtdparts = %s\n\n", p);
+
+ /* delete all devices and partitions */
+ if (mtd_devices_init() != 0) {
+ printf("could not initialise device list\n");
+ return err;
+ }
+
+ /* re-read 'mtdparts' variable, mtd_devices_init may be updating env */
+ p = getenv("mtdparts");
+
+ if (strncmp(p, "mtdparts=", 9) != 0) {
+ printf("mtdparts variable doesn't start with 'mtdparts='\n");
+ return err;
+ }
+ p += 9;
+
+ while (p && (*p != '\0')) {
+ err = 1;
+ if ((device_parse(p, &p, &dev) != 0) || (!dev))
+ break;
+
+ DEBUGF("+ device: %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type),
+ dev->id->num, dev->id->mtd_id);
+
+ /* check if parsed device is already on the list */
+ if (device_find(dev->id->type, dev->id->num) != NULL) {
+ printf("device %s%d redefined, please correct mtdparts variable\n",
+ MTD_DEV_TYPE(dev->id->type), dev->id->num);
+ break;
+ }
+
+ list_add_tail(&dev->link, &devices);
+ err = 0;
+ }
+ if (err == 1) {
+ device_delall(&devices);
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * Parse provided string describing mtdids mapping (see file header for mtdids
+ * variable format). Allocate memory for each entry and add all found entries
+ * to the global mtdids list.
+ *
+ * @param ids mapping string
+ * @return 0 on success, 1 otherwise
+ */
+static int parse_mtdids(const char *const ids)
+{
+ const char *p = ids;
+ const char *mtd_id;
+ int mtd_id_len;
+ struct mtdids *id;
+ struct list_head *entry, *n;
+ struct mtdids *id_tmp;
+ u8 type, num;
+ u32 size;
+ int ret = 1;
+
+ DEBUGF("\n---parse_mtdids---\nmtdids = %s\n\n", ids);
+
+ /* clean global mtdids list */
+ list_for_each_safe(entry, n, &mtdids) {
+ id_tmp = list_entry(entry, struct mtdids, link);
+ DEBUGF("mtdids del: %d %d\n", id_tmp->type, id_tmp->num);
+ list_del(entry);
+ free(id_tmp);
+ }
+ last_ids[0] = '\0';
+ INIT_LIST_HEAD(&mtdids);
+
+ while(p && (*p != '\0')) {
+
+ ret = 1;
+ /* parse 'nor'|'nand'|'onenand'<dev-num> */
+ if (mtd_id_parse(p, &p, &type, &num) != 0)
+ break;
+
+ if (*p != '=') {
+ printf("mtdids: incorrect <dev-num>\n");
+ break;
+ }
+ p++;
+
+ /* check if requested device exists */
+ if (mtd_device_validate(type, num, &size) != 0)
+ return 1;
+
+ /* locate <mtd-id> */
+ mtd_id = p;
+ if ((p = strchr(mtd_id, ',')) != NULL) {
+ mtd_id_len = p - mtd_id + 1;
+ p++;
+ } else {
+ mtd_id_len = strlen(mtd_id) + 1;
+ }
+ if (mtd_id_len == 0) {
+ printf("mtdids: no <mtd-id> identifier\n");
+ break;
+ }
+
+ /* check if this id is already on the list */
+ int double_entry = 0;
+ list_for_each(entry, &mtdids) {
+ id_tmp = list_entry(entry, struct mtdids, link);
+ if ((id_tmp->type == type) && (id_tmp->num == num)) {
+ double_entry = 1;
+ break;
+ }
+ }
+ if (double_entry) {
+ printf("device id %s%d redefined, please correct mtdids variable\n",
+ MTD_DEV_TYPE(type), num);
+ break;
+ }
+
+ /* allocate mtdids structure */
+ if (!(id = (struct mtdids *)malloc(sizeof(struct mtdids) + mtd_id_len))) {
+ printf("out of memory\n");
+ break;
+ }
+ memset(id, 0, sizeof(struct mtdids) + mtd_id_len);
+ id->num = num;
+ id->type = type;
+ id->size = size;
+ id->mtd_id = (char *)(id + 1);
+ strncpy(id->mtd_id, mtd_id, mtd_id_len - 1);
+ id->mtd_id[mtd_id_len - 1] = '\0';
+ INIT_LIST_HEAD(&id->link);
+
+ DEBUGF("+ id %s%d\t%16d bytes\t%s\n",
+ MTD_DEV_TYPE(id->type), id->num,
+ id->size, id->mtd_id);
+
+ list_add_tail(&id->link, &mtdids);
+ ret = 0;
+ }
+ if (ret == 1) {
+ /* clean mtdids list and free allocated memory */
+ list_for_each_safe(entry, n, &mtdids) {
+ id_tmp = list_entry(entry, struct mtdids, link);
+ list_del(entry);
+ free(id_tmp);
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * Parse and initialize global mtdids mapping and create global
+ * device/partition list.
+ *
+ * @return 0 on success, 1 otherwise
+ */
+int mtdparts_init(void)
+{
+ static int initialized = 0;
+ const char *ids, *parts;
+ const char *current_partition;
+ int ids_changed;
+ char tmp_ep[PARTITION_MAXLEN];
+
+ DEBUGF("\n---mtdparts_init---\n");
+ if (!initialized) {
+ INIT_LIST_HEAD(&mtdids);
+ INIT_LIST_HEAD(&devices);
+ memset(last_ids, 0, MTDIDS_MAXLEN);
+ memset(last_parts, 0, MTDPARTS_MAXLEN);
+ memset(last_partition, 0, PARTITION_MAXLEN);
+ initialized = 1;
+ }
+
+ /* get variables */
+ ids = getenv("mtdids");
+ parts = getenv("mtdparts");
+ current_partition = getenv("partition");
+
+ /* save it for later parsing, cannot rely on current partition pointer
+ * as 'partition' variable may be updated during init */
+ tmp_ep[0] = '\0';
+ if (current_partition)
+ strncpy(tmp_ep, current_partition, PARTITION_MAXLEN);
+
+ DEBUGF("last_ids : %s\n", last_ids);
+ DEBUGF("env_ids : %s\n", ids);
+ DEBUGF("last_parts: %s\n", last_parts);
+ DEBUGF("env_parts : %s\n\n", parts);
+
+ DEBUGF("last_partition : %s\n", last_partition);
+ DEBUGF("env_partition : %s\n", current_partition);
+
+ /* if mtdids varible is empty try to use defaults */
+ if (!ids) {
+ if (mtdids_default) {
+ DEBUGF("mtdids variable not defined, using default\n");
+ ids = mtdids_default;
+ setenv("mtdids", (char *)ids);
+ } else {
+ printf("mtdids not defined, no default present\n");
+ return 1;
+ }
+ }
+ if (strlen(ids) > MTDIDS_MAXLEN - 1) {
+ printf("mtdids too long (> %d)\n", MTDIDS_MAXLEN);
+ return 1;
+ }
+
+ /* do no try to use defaults when mtdparts variable is not defined,
+ * just check the length */
+ if (!parts)
+ printf("mtdparts variable not set, see 'help mtdparts'\n");
+
+ if (parts && (strlen(parts) > MTDPARTS_MAXLEN - 1)) {
+ printf("mtdparts too long (> %d)\n", MTDPARTS_MAXLEN);
+ return 1;
+ }
+
+ /* check if we have already parsed those mtdids */
+ if ((last_ids[0] != '\0') && (strcmp(last_ids, ids) == 0)) {
+ ids_changed = 0;
+ } else {
+ ids_changed = 1;
+
+ if (parse_mtdids(ids) != 0) {
+ mtd_devices_init();
+ return 1;
+ }
+
+ /* ok it's good, save new ids */
+ strncpy(last_ids, ids, MTDIDS_MAXLEN);
+ }
+
+ /* parse partitions if either mtdparts or mtdids were updated */
+ if (parts && ((last_parts[0] == '\0') || ((strcmp(last_parts, parts) != 0)) || ids_changed)) {
+ if (parse_mtdparts(parts) != 0)
+ return 1;
+
+ if (list_empty(&devices)) {
+ printf("mtdparts_init: no valid partitions\n");
+ return 1;
+ }
+
+ /* ok it's good, save new parts */
+ strncpy(last_parts, parts, MTDPARTS_MAXLEN);
+
+ /* reset first partition from first dev from the list as current */
+ current_dev = list_entry(devices.next, struct mtd_device, link);
+ current_partnum = 0;
+ current_save();
+
+ DEBUGF("mtdparts_init: current_dev = %s%d, current_partnum = %d\n",
+ MTD_DEV_TYPE(current_dev->id->type),
+ current_dev->id->num, current_partnum);
+ }
+
+ /* mtdparts variable was reset to NULL, delete all devices/partitions */
+ if (!parts && (last_parts[0] != '\0'))
+ return mtd_devices_init();
+
+ /* do not process current partition if mtdparts variable is null */
+ if (!parts)
+ return 0;
+
+ /* is current partition set in environment? if so, use it */
+ if ((tmp_ep[0] != '\0') && (strcmp(tmp_ep, last_partition) != 0)) {
+ struct part_info *p;
+ struct mtd_device *cdev;
+ u8 pnum;
+
+ DEBUGF("--- getting current partition: %s\n", tmp_ep);
+
+ if (find_dev_and_part(tmp_ep, &cdev, &pnum, &p) == 0) {
+ current_dev = cdev;
+ current_partnum = pnum;
+ current_save();
+ }
+ } else if (getenv("partition") == NULL) {
+ DEBUGF("no partition variable set, setting...\n");
+ current_save();
+ }
+
+ return 0;
+}
+
+/**
+ * Return pointer to the partition of a requested number from a requested
+ * device.
+ *
+ * @param dev device that is to be searched for a partition
+ * @param part_num requested partition number
+ * @return pointer to the part_info, NULL otherwise
+ */
+static struct part_info* mtd_part_info(struct mtd_device *dev, unsigned int part_num)
+{
+ struct list_head *entry;
+ struct part_info *part;
+ int num;
+
+ if (!dev)
+ return NULL;
+
+ DEBUGF("\n--- mtd_part_info: partition number %d for device %s%d (%s)\n",
+ part_num, MTD_DEV_TYPE(dev->id->type),
+ dev->id->num, dev->id->mtd_id);
+
+ if (part_num >= dev->num_parts) {
+ printf("invalid partition number %d for device %s%d (%s)\n",
+ part_num, MTD_DEV_TYPE(dev->id->type),
+ dev->id->num, dev->id->mtd_id);
+ return NULL;
+ }
+
+ /* locate partition number, return it */
+ num = 0;
+ list_for_each(entry, &dev->parts) {
+ part = list_entry(entry, struct part_info, link);
+
+ if (part_num == num++) {
+ return part;
+ }
+ }
+
+ return NULL;
+}
+
+/***************************************************/
+/* U-boot commands */
+/***************************************************/
+/* command line only */
+/**
+ * Routine implementing u-boot chpart command. Sets new current partition based
+ * on the user supplied partition id. For partition id format see find_dev_and_part().
+ *
+ * @param cmdtp command internal data
+ * @param flag command flag
+ * @param argc number of arguments supplied to the command
+ * @param argv arguments list
+ * @return 0 on success, 1 otherwise
+ */
+int do_chpart(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+/* command line only */
+ struct mtd_device *dev;
+ struct part_info *part;
+ u8 pnum;
+
+ if (mtdparts_init() !=0)
+ return 1;
+
+ if (argc < 2) {
+ printf("no partition id specified\n");
+ return 1;
+ }
+
+ if (find_dev_and_part(argv[1], &dev, &pnum, &part) != 0)
+ return 1;
+
+ current_dev = dev;
+ current_partnum = pnum;
+ current_save();
+
+ printf("partition changed to %s%d,%d\n",
+ MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum);
+
+ return 0;
+}
+
+/**
+ * Routine implementing u-boot mtdparts command. Initialize/update default global
+ * partition list and process user partition request (list, add, del).
+ *
+ * @param cmdtp command internal data
+ * @param flag command flag
+ * @param argc number of arguments supplied to the command
+ * @param argv arguments list
+ * @return 0 on success, 1 otherwise
+ */
+int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ if (argc == 2) {
+ if (strcmp(argv[1], "default") == 0) {
+ setenv("mtdids", (char *)mtdids_default);
+ setenv("mtdparts", (char *)mtdparts_default);
+ setenv("partition", NULL);
+
+ mtdparts_init();
+ return 0;
+ } else if (strcmp(argv[1], "delall") == 0) {
+ /* this may be the first run, initialize lists if needed */
+ mtdparts_init();
+
+ setenv("mtdparts", NULL);
+
+ /* mtd_devices_init() calls current_save() */
+ return mtd_devices_init();
+ }
+ }
+
+ /* make sure we are in sync with env variables */
+ if (mtdparts_init() != 0)
+ return 1;
+
+ if (argc == 1) {
+ list_partitions();
+ return 0;
+ }
+
+ /* mtdparts add <mtd-dev> <size>[@<offset>] <name> [ro] */
+ if (((argc == 5) || (argc == 6)) && (strcmp(argv[1], "add") == 0)) {
+#define PART_ADD_DESC_MAXLEN 64
+ char tmpbuf[PART_ADD_DESC_MAXLEN];
+ u8 type, num, len;
+ struct mtd_device *dev;
+ struct mtd_device *dev_tmp;
+ struct mtdids *id;
+ struct part_info *p;
+
+ if (mtd_id_parse(argv[2], NULL, &type, &num) != 0)
+ return 1;
+
+ if ((id = id_find(type, num)) == NULL) {
+ printf("no such device %s defined in mtdids variable\n", argv[2]);
+ return 1;
+ }
+
+ len = strlen(id->mtd_id) + 1; /* 'mtd_id:' */
+ len += strlen(argv[3]); /* size@offset */
+ len += strlen(argv[4]) + 2; /* '(' name ')' */
+ if (argv[5] && (strlen(argv[5]) == 2))
+ len += 2; /* 'ro' */
+
+ if (len >= PART_ADD_DESC_MAXLEN) {
+ printf("too long partition description\n");
+ return 1;
+ }
+ sprintf(tmpbuf, "%s:%s(%s)%s",
+ id->mtd_id, argv[3], argv[4], argv[5] ? argv[5] : "");
+ DEBUGF("add tmpbuf: %s\n", tmpbuf);
+
+ if ((device_parse(tmpbuf, NULL, &dev) != 0) || (!dev))
+ return 1;
+
+ DEBUGF("+ %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type),
+ dev->id->num, dev->id->mtd_id);
+
+ if ((dev_tmp = device_find(dev->id->type, dev->id->num)) == NULL) {
+ device_add(dev);
+ } else {
+ /* merge new partition with existing ones*/
+ p = list_entry(dev->parts.next, struct part_info, link);
+ if (part_add(dev_tmp, p) != 0) {
+ device_del(dev);
+ return 1;
+ }
+ }
+
+ if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) {
+ printf("generated mtdparts too long, reseting to null\n");
+ return 1;
+ }
+
+ return 0;
+ }
+
+ /* mtdparts del part-id */
+ if ((argc == 3) && (strcmp(argv[1], "del") == 0)) {
+ DEBUGF("del: part-id = %s\n", argv[2]);
+
+ return delete_partition(argv[2]);
+ }
+
+ cmd_usage(cmdtp);
+ return 1;
+}
+
+/***************************************************/
+U_BOOT_CMD(
+ chpart, 2, 0, do_chpart,
+ "change active partition",
+ "part-id\n"
+ " - change active partition (e.g. part-id = nand0,1)\n"
+);
+
+U_BOOT_CMD(
+ mtdparts, 6, 0, do_mtdparts,
+ "define flash/nand partitions",
+ "\n"
+ " - list partition table\n"
+ "mtdparts delall\n"
+ " - delete all partitions\n"
+ "mtdparts del part-id\n"
+ " - delete partition (e.g. part-id = nand0,1)\n"
+ "mtdparts add <mtd-dev> <size>[@<offset>] [<name>] [ro]\n"
+ " - add partition\n"
+ "mtdparts default\n"
+ " - reset partition table to defaults\n\n"
+ "-----\n\n"
+ "this command uses three environment variables:\n\n"
+ "'partition' - keeps current partition identifier\n\n"
+ "partition := <part-id>\n"
+ "<part-id> := <dev-id>,part_num\n\n"
+ "'mtdids' - linux kernel mtd device id <-> u-boot device id mapping\n\n"
+ "mtdids=<idmap>[,<idmap>,...]\n\n"
+ "<idmap> := <dev-id>=<mtd-id>\n"
+ "<dev-id> := 'nand'|'nor'|'onenand'<dev-num>\n"
+ "<dev-num> := mtd device number, 0...\n"
+ "<mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)\n\n"
+ "'mtdparts' - partition list\n\n"
+ "mtdparts=mtdparts=<mtd-def>[;<mtd-def>...]\n\n"
+ "<mtd-def> := <mtd-id>:<part-def>[,<part-def>...]\n"
+ "<mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)\n"
+ "<part-def> := <size>[@<offset>][<name>][<ro-flag>]\n"
+ "<size> := standard linux memsize OR '-' to denote all remaining space\n"
+ "<offset> := partition start offset within the device\n"
+ "<name> := '(' NAME ')'\n"
+ "<ro-flag> := when set to 'ro' makes partition read-only (not used, passed to kernel)\n"
+);
+/***************************************************/
diff --git a/common/cmd_nand.c b/common/cmd_nand.c
index e6623ca..04b3200 100644
--- a/common/cmd_nand.c
+++ b/common/cmd_nand.c
@@ -29,7 +29,7 @@
#include <jffs2/jffs2.h>
#include <nand.h>
-#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
/* parition handling routines */
int mtdparts_init(void);
@@ -105,7 +105,7 @@ static int
arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off, size_t *size)
{
int idx = nand_curr_device;
-#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
struct mtd_device *dev;
struct part_info *part;
u8 pnum;
@@ -153,7 +153,7 @@ arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off, size_t *size
*size = nand->size - *off;
}
-#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
out:
#endif
printf("device %d ", idx);
@@ -589,7 +589,7 @@ int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
char *boot_device = NULL;
int idx;
ulong addr, offset = 0;
-#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
struct mtd_device *dev;
struct part_info *part;
u8 pnum;
@@ -634,7 +634,7 @@ int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
offset = simple_strtoul(argv[3], NULL, 16);
break;
default:
-#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
usage:
#endif
cmd_usage(cmdtp);
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 68c673e..95eebb5 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -283,18 +283,6 @@ int _do_setenv (int flag, int argc, char *argv[])
*++env = '\0';
}
-#ifdef CONFIG_NET_MULTI
- if (strncmp(name, "eth", 3) == 0) {
- char *end;
- int num = simple_strtoul(name+3, &end, 10);
-
- if (strcmp(end, "addr") == 0) {
- eth_set_enetaddr(num, argv[2]);
- }
- }
-#endif
-
-
/* Delete only ? */
if ((argc < 3) || argv[2] == NULL) {
env_crc_update ();
@@ -342,18 +330,8 @@ int _do_setenv (int flag, int argc, char *argv[])
* entry in the enviornment is changed
*/
- if (strcmp(argv[1],"ethaddr") == 0) {
- char *s = argv[2]; /* always use only one arg */
- char *e;
- for (i=0; i<6; ++i) {
- bd->bi_enetaddr[i] = s ? simple_strtoul(s, &e, 16) : 0;
- if (s) s = (*e) ? e+1 : e;
- }
-#ifdef CONFIG_NET_MULTI
- eth_set_enetaddr(0, argv[2]);
-#endif
+ if (strcmp(argv[1],"ethaddr") == 0)
return 0;
- }
if (strcmp(argv[1],"ipaddr") == 0) {
char *s = argv[2]; /* always use only one arg */
diff --git a/common/cmd_ubifs.c b/common/cmd_ubifs.c
new file mode 100644
index 0000000..b2e0f4f
--- /dev/null
+++ b/common/cmd_ubifs.c
@@ -0,0 +1,132 @@
+/*
+ * (C) Copyright 2008
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+
+/*
+ * UBIFS command support
+ */
+
+#undef DEBUG
+
+#include <common.h>
+#include <config.h>
+#include <command.h>
+
+static int ubifs_initialized;
+static int ubifs_mounted;
+
+/* Prototypes */
+int ubifs_init(void);
+int ubifs_mount(char *vol_name);
+int ubifs_ls(char *dir_name);
+int ubifs_load(char *filename, u32 addr, u32 size);
+
+int do_ubifs_mount(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ char *vol_name;
+ int ret;
+
+ vol_name = argv[1];
+ debug("Using volume %s\n", vol_name);
+
+ if (ubifs_initialized == 0) {
+ ubifs_init();
+ ubifs_initialized = 1;
+ }
+
+ ret = ubifs_mount(vol_name);
+ if (ret)
+ return -1;
+
+ ubifs_mounted = 1;
+
+ return 0;
+}
+
+int do_ubifs_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ char *filename = "/";
+ int ret;
+
+ if (!ubifs_mounted) {
+ printf("UBIFS not mounted, use ubifs mount to mount volume first!\n");
+ return -1;
+ }
+
+ if (argc == 2)
+ filename = argv[1];
+ debug("Using filename %s\n", filename);
+
+ ret = ubifs_ls(filename);
+ if (ret)
+ printf("%s not found!\n", filename);
+
+ return ret;
+}
+
+int do_ubifs_load(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ char *filename;
+ int ret;
+ u32 addr;
+ u32 size = 0;
+
+ if (!ubifs_mounted) {
+ printf("UBIFS not mounted, use ubifs mount to mount volume first!\n");
+ return -1;
+ }
+
+ if (argc < 3) {
+ printf("Usage:\n%s\n", cmdtp->usage);
+ return -1;
+ }
+
+ addr = simple_strtoul(argv[1], NULL, 16);
+ filename = argv[2];
+
+ if (argc == 4)
+ size = simple_strtoul(argv[3], NULL, 16);
+ debug("Loading file '%s' to address 0x%08x (size %d)\n", filename, addr, size);
+
+ ret = ubifs_load(filename, addr, size);
+ if (ret)
+ printf("%s not found!\n", filename);
+
+ return ret;
+}
+
+U_BOOT_CMD(
+ ubifsmount, 2, 0, do_ubifs_mount,
+ "ubifsmount- mount UBIFS volume\n",
+ "\n");
+
+U_BOOT_CMD(ubifsls, 2, 0, do_ubifs_ls,
+ "ubifsls - list files in a directory\n",
+ "[directory]\n"
+ " - list files in a 'directory' (default '/')\n");
+
+U_BOOT_CMD(ubifsload, 4, 0, do_ubifs_load,
+ "ubifsload- load file from an UBIFS filesystem\n",
+ "<addr> <filename> [bytes]\n"
+ " - load file 'filename' to address 'addr'\n");
diff --git a/common/lynxkdi.c b/common/lynxkdi.c
index 5f12b0d..17b0607 100644
--- a/common/lynxkdi.c
+++ b/common/lynxkdi.c
@@ -33,7 +33,7 @@ void lynxkdi_boot (image_header_t *hdr)
kbd = gd->bd;
parms->clock_ref = kbd->bi_busfreq;
parms->dramsz = kbd->bi_memsize;
- memcpy (parms->ethaddr, kbd->bi_enetaddr, 6);
+ eth_getenv_enetaddr("ethaddr", parms->ethaddr);
mtspr (SPRN_SPRG2, 0x0020);
/* Do a simple check for Bluecat so we can pass the
diff --git a/cpu/arm920t/at91rm9200/ether.c b/cpu/arm920t/at91rm9200/ether.c
index f20e070..b00b948 100644
--- a/cpu/arm920t/at91rm9200/ether.c
+++ b/cpu/arm920t/at91rm9200/ether.c
@@ -155,6 +155,7 @@ int eth_init (bd_t * bd)
{
int ret;
int i;
+ uchar enetaddr[6];
p_mac = AT91C_BASE_EMAC;
@@ -190,9 +191,10 @@ int eth_init (bd_t * bd)
rbfdt[RBF_FRAMEMAX - 1].addr |= RBF_WRAP;
rbfp = &rbfdt[0];
- p_mac->EMAC_SA2L = (bd->bi_enetaddr[3] << 24) | (bd->bi_enetaddr[2] << 16)
- | (bd->bi_enetaddr[1] << 8) | (bd->bi_enetaddr[0]);
- p_mac->EMAC_SA2H = (bd->bi_enetaddr[5] << 8) | (bd->bi_enetaddr[4]);
+ eth_getenv_enetaddr("ethaddr", enetaddr);
+ p_mac->EMAC_SA2L = (enetaddr[3] << 24) | (enetaddr[2] << 16)
+ | (enetaddr[1] << 8) | (enetaddr[0]);
+ p_mac->EMAC_SA2H = (enetaddr[5] << 8) | (enetaddr[4]);
p_mac->EMAC_RBQP = (long) (&rbfdt[0]);
p_mac->EMAC_RSR &= ~(AT91C_EMAC_RSR_OVR | AT91C_EMAC_REC | AT91C_EMAC_BNA);
diff --git a/cpu/arm926ejs/at91/u-boot.lds b/cpu/arm926ejs/at91/u-boot.lds
index 4778d1e..ebb1f93 100644
--- a/cpu/arm926ejs/at91/u-boot.lds
+++ b/cpu/arm926ejs/at91/u-boot.lds
@@ -37,7 +37,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/cpu/i386/Makefile b/cpu/i386/Makefile
index 761c4f6..e98bd3d 100644
--- a/cpu/i386/Makefile
+++ b/cpu/i386/Makefile
@@ -29,7 +29,7 @@ include $(TOPDIR)/config.mk
LIB = $(obj)lib$(CPU).a
START = start.o start16.o resetvec.o
-COBJS = serial.o interrupts.o cpu.o timer.o
+COBJS = serial.o interrupts.o exceptions.o cpu.o
SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
diff --git a/cpu/i386/cpu.c b/cpu/i386/cpu.c
index b9af5f8..d91e33b 100644
--- a/cpu/i386/cpu.c
+++ b/cpu/i386/cpu.c
@@ -46,6 +46,10 @@ int cpu_init(void)
"orl $0x22, %eax\n" \
"movl %eax, %cr0\n" );
+ /* Initialize core interrupt and exception functionality of CPU */
+ cpu_init_interrupts ();
+ cpu_init_exceptions ();
+
return 0;
}
diff --git a/cpu/i386/exceptions.c b/cpu/i386/exceptions.c
new file mode 100644
index 0000000..bc3d434
--- /dev/null
+++ b/cpu/i386/exceptions.c
@@ -0,0 +1,229 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/interrupt.h>
+
+asm (".globl exp_return\n"
+ "exp_return:\n"
+ " addl $12, %esp\n"
+ " pop %esp\n"
+ " popa\n"
+ " iret\n");
+
+char exception_stack[4096];
+
+/*
+ * For detailed description of each exception, refer to:
+ * Intel® 64 and IA-32 Architectures Software Developer's Manual
+ * Volume 1: Basic Architecture
+ * Order Number: 253665-029US, November 2008
+ * Table 6-1. Exceptions and Interrupts
+ */
+DECLARE_EXCEPTION(0, divide_error_entry);
+DECLARE_EXCEPTION(1, debug_entry);
+DECLARE_EXCEPTION(2, nmi_interrupt_entry);
+DECLARE_EXCEPTION(3, breakpoint_entry);
+DECLARE_EXCEPTION(4, overflow_entry);
+DECLARE_EXCEPTION(5, bound_range_exceeded_entry);
+DECLARE_EXCEPTION(6, invalid_opcode_entry);
+DECLARE_EXCEPTION(7, device_not_available_entry);
+DECLARE_EXCEPTION(8, double_fault_entry);
+DECLARE_EXCEPTION(9, coprocessor_segment_overrun_entry);
+DECLARE_EXCEPTION(10, invalid_tss_entry);
+DECLARE_EXCEPTION(11, segment_not_present_entry);
+DECLARE_EXCEPTION(12, stack_segment_fault_entry);
+DECLARE_EXCEPTION(13, general_protection_entry);
+DECLARE_EXCEPTION(14, page_fault_entry);
+DECLARE_EXCEPTION(15, reserved_exception_entry);
+DECLARE_EXCEPTION(16, floating_point_error_entry);
+DECLARE_EXCEPTION(17, alignment_check_entry);
+DECLARE_EXCEPTION(18, machine_check_entry);
+DECLARE_EXCEPTION(19, simd_floating_point_exception_entry);
+DECLARE_EXCEPTION(20, reserved_exception_entry);
+DECLARE_EXCEPTION(21, reserved_exception_entry);
+DECLARE_EXCEPTION(22, reserved_exception_entry);
+DECLARE_EXCEPTION(23, reserved_exception_entry);
+DECLARE_EXCEPTION(24, reserved_exception_entry);
+DECLARE_EXCEPTION(25, reserved_exception_entry);
+DECLARE_EXCEPTION(26, reserved_exception_entry);
+DECLARE_EXCEPTION(27, reserved_exception_entry);
+DECLARE_EXCEPTION(28, reserved_exception_entry);
+DECLARE_EXCEPTION(29, reserved_exception_entry);
+DECLARE_EXCEPTION(30, reserved_exception_entry);
+DECLARE_EXCEPTION(31, reserved_exception_entry);
+
+__isr__ reserved_exception_entry(int cause, int ip, int seg)
+{
+ printf("Reserved Exception %d at %04x:%08x\n", cause, seg, ip);
+}
+
+__isr__ divide_error_entry(int cause, int ip, int seg)
+{
+ printf("Divide Error (Division by zero) at %04x:%08x\n", seg, ip);
+ while(1);
+}
+
+__isr__ debug_entry(int cause, int ip, int seg)
+{
+ printf("Debug Interrupt (Single step) at %04x:%08x\n", seg, ip);
+}
+
+__isr__ nmi_interrupt_entry(int cause, int ip, int seg)
+{
+ printf("NMI Interrupt at %04x:%08x\n", seg, ip);
+}
+
+__isr__ breakpoint_entry(int cause, int ip, int seg)
+{
+ printf("Breakpoint at %04x:%08x\n", seg, ip);
+}
+
+__isr__ overflow_entry(int cause, int ip, int seg)
+{
+ printf("Overflow at %04x:%08x\n", seg, ip);
+ while(1);
+}
+
+__isr__ bound_range_exceeded_entry(int cause, int ip, int seg)
+{
+ printf("BOUND Range Exceeded at %04x:%08x\n", seg, ip);
+ while(1);
+}
+
+__isr__ invalid_opcode_entry(int cause, int ip, int seg)
+{
+ printf("Invalid Opcode (UnDefined Opcode) at %04x:%08x\n", seg, ip);
+ while(1);
+}
+
+__isr__ device_not_available_entry(int cause, int ip, int seg)
+{
+ printf("Device Not Available (No Math Coprocessor) at %04x:%08x\n", seg, ip);
+ while(1);
+}
+
+__isr__ double_fault_entry(int cause, int ip, int seg)
+{
+ printf("Double fault at %04x:%08x\n", seg, ip);
+ while(1);
+}
+
+__isr__ coprocessor_segment_overrun_entry(int cause, int ip, int seg)
+{
+ printf("Co-processor segment overrun at %04x:%08x\n", seg, ip);
+ while(1);
+}
+
+__isr__ invalid_tss_entry(int cause, int ip, int seg)
+{
+ printf("Invalid TSS at %04x:%08x\n", seg, ip);
+}
+
+__isr__ segment_not_present_entry(int cause, int ip, int seg)
+{
+ printf("Segment Not Present at %04x:%08x\n", seg, ip);
+ while(1);
+}
+
+__isr__ stack_segment_fault_entry(int cause, int ip, int seg)
+{
+ printf("Stack Segment Fault at %04x:%08x\n", seg, ip);
+ while(1);
+}
+
+__isr__ general_protection_entry(int cause, int ip, int seg)
+{
+ printf("General Protection at %04x:%08x\n", seg, ip);
+}
+
+__isr__ page_fault_entry(int cause, int ip, int seg)
+{
+ printf("Page fault at %04x:%08x\n", seg, ip);
+ while(1);
+}
+
+__isr__ floating_point_error_entry(int cause, int ip, int seg)
+{
+ printf("Floating-Point Error (Math Fault) at %04x:%08x\n", seg, ip);
+}
+
+__isr__ alignment_check_entry(int cause, int ip, int seg)
+{
+ printf("Alignment check at %04x:%08x\n", seg, ip);
+}
+
+__isr__ machine_check_entry(int cause, int ip, int seg)
+{
+ printf("Machine Check at %04x:%08x\n", seg, ip);
+}
+
+__isr__ simd_floating_point_exception_entry(int cause, int ip, int seg)
+{
+ printf("SIMD Floating-Point Exception at %04x:%08x\n", seg, ip);
+}
+
+int cpu_init_exceptions(void)
+{
+ /* Just in case... */
+ disable_interrupts();
+
+ /* Setup exceptions */
+ set_vector(0x00, exp_0);
+ set_vector(0x01, exp_1);
+ set_vector(0x02, exp_2);
+ set_vector(0x03, exp_3);
+ set_vector(0x04, exp_4);
+ set_vector(0x05, exp_5);
+ set_vector(0x06, exp_6);
+ set_vector(0x07, exp_7);
+ set_vector(0x08, exp_8);
+ set_vector(0x09, exp_9);
+ set_vector(0x0a, exp_10);
+ set_vector(0x0b, exp_11);
+ set_vector(0x0c, exp_12);
+ set_vector(0x0d, exp_13);
+ set_vector(0x0e, exp_14);
+ set_vector(0x0f, exp_15);
+ set_vector(0x10, exp_16);
+ set_vector(0x11, exp_17);
+ set_vector(0x12, exp_18);
+ set_vector(0x13, exp_19);
+ set_vector(0x14, exp_20);
+ set_vector(0x15, exp_21);
+ set_vector(0x16, exp_22);
+ set_vector(0x17, exp_23);
+ set_vector(0x18, exp_24);
+ set_vector(0x19, exp_25);
+ set_vector(0x1a, exp_26);
+ set_vector(0x1b, exp_27);
+ set_vector(0x1c, exp_28);
+ set_vector(0x1d, exp_29);
+ set_vector(0x1e, exp_30);
+ set_vector(0x1f, exp_31);
+
+ /* It is now safe to enable interrupts */
+ enable_interrupts();
+
+ return 0;
+}
diff --git a/cpu/i386/interrupts.c b/cpu/i386/interrupts.c
index badb30b..063ea42 100644
--- a/cpu/i386/interrupts.c
+++ b/cpu/i386/interrupts.c
@@ -22,10 +22,6 @@
*/
#include <common.h>
-#include <malloc.h>
-#include <asm/io.h>
-#include <asm/i8259.h>
-#include <asm/ibmpc.h>
#include <asm/interrupt.h>
@@ -41,361 +37,34 @@ struct idt_entry {
struct idt_entry idt[256];
-#define MAX_IRQ 16
-
-typedef struct irq_handler {
- struct irq_handler *next;
- interrupt_handler_t* isr_func;
- void *isr_data;
-} irq_handler_t;
-
-#define IRQ_DISABLED 1
-
-typedef struct {
- irq_handler_t *handler;
- unsigned long status;
-} irq_desc_t;
-
-static irq_desc_t irq_table[MAX_IRQ];
-
-asm ("irq_return:\n"
+asm (".globl irq_return\n"
+ "irq_return:\n"
" addl $4, %esp\n"
" popa\n"
" iret\n");
-asm ("exp_return:\n"
- " addl $12, %esp\n"
- " pop %esp\n"
- " popa\n"
- " iret\n");
-
-char exception_stack[4096];
-
-#define DECLARE_INTERRUPT(x) \
- asm(".globl irq_"#x"\n" \
- "irq_"#x":\n" \
- "pusha \n" \
- "pushl $"#x"\n" \
- "pushl $irq_return\n" \
- "jmp do_irq\n"); \
- void __attribute__ ((regparm(0))) irq_##x(void)
-
-#define DECLARE_EXCEPTION(x, f) \
- asm(".globl exp_"#x"\n" \
- "exp_"#x":\n" \
- "pusha \n" \
- "movl %esp, %ebx\n" \
- "movl $exception_stack, %eax\n" \
- "movl %eax, %esp \n" \
- "pushl %ebx\n" \
- "movl 32(%esp), %ebx\n" \
- "xorl %edx, %edx\n" \
- "movw 36(%esp), %dx\n" \
- "pushl %edx\n" \
- "pushl %ebx\n" \
- "pushl $"#x"\n" \
- "pushl $exp_return\n" \
- "jmp "#f"\n"); \
- void __attribute__ ((regparm(0))) exp_##x(void)
-
-DECLARE_EXCEPTION(0, divide_exception_entry); /* Divide exception */
-DECLARE_EXCEPTION(1, debug_exception_entry); /* Debug exception */
-DECLARE_EXCEPTION(2, nmi_entry); /* NMI */
-DECLARE_EXCEPTION(3, unknown_exception_entry); /* Breakpoint/Coprocessor Error */
-DECLARE_EXCEPTION(4, unknown_exception_entry); /* Overflow */
-DECLARE_EXCEPTION(5, unknown_exception_entry); /* Bounds */
-DECLARE_EXCEPTION(6, invalid_instruction_entry); /* Invalid instruction */
-DECLARE_EXCEPTION(7, unknown_exception_entry); /* Device not present */
-DECLARE_EXCEPTION(8, double_fault_entry); /* Double fault */
-DECLARE_EXCEPTION(9, unknown_exception_entry); /* Co-processor segment overrun */
-DECLARE_EXCEPTION(10, invalid_tss_exception_entry);/* Invalid TSS */
-DECLARE_EXCEPTION(11, seg_fault_entry); /* Segment not present */
-DECLARE_EXCEPTION(12, stack_fault_entry); /* Stack overflow */
-DECLARE_EXCEPTION(13, gpf_entry); /* GPF */
-DECLARE_EXCEPTION(14, page_fault_entry); /* PF */
-DECLARE_EXCEPTION(15, unknown_exception_entry); /* Reserved */
-DECLARE_EXCEPTION(16, fp_exception_entry); /* Floating point */
-DECLARE_EXCEPTION(17, alignment_check_entry); /* alignment check */
-DECLARE_EXCEPTION(18, machine_check_entry); /* machine check */
-DECLARE_EXCEPTION(19, unknown_exception_entry); /* Reserved */
-DECLARE_EXCEPTION(20, unknown_exception_entry); /* Reserved */
-DECLARE_EXCEPTION(21, unknown_exception_entry); /* Reserved */
-DECLARE_EXCEPTION(22, unknown_exception_entry); /* Reserved */
-DECLARE_EXCEPTION(23, unknown_exception_entry); /* Reserved */
-DECLARE_EXCEPTION(24, unknown_exception_entry); /* Reserved */
-DECLARE_EXCEPTION(25, unknown_exception_entry); /* Reserved */
-DECLARE_EXCEPTION(26, unknown_exception_entry); /* Reserved */
-DECLARE_EXCEPTION(27, unknown_exception_entry); /* Reserved */
-DECLARE_EXCEPTION(28, unknown_exception_entry); /* Reserved */
-DECLARE_EXCEPTION(29, unknown_exception_entry); /* Reserved */
-DECLARE_EXCEPTION(30, unknown_exception_entry); /* Reserved */
-DECLARE_EXCEPTION(31, unknown_exception_entry); /* Reserved */
-
-DECLARE_INTERRUPT(0);
-DECLARE_INTERRUPT(1);
-DECLARE_INTERRUPT(3);
-DECLARE_INTERRUPT(4);
-DECLARE_INTERRUPT(5);
-DECLARE_INTERRUPT(6);
-DECLARE_INTERRUPT(7);
-DECLARE_INTERRUPT(8);
-DECLARE_INTERRUPT(9);
-DECLARE_INTERRUPT(10);
-DECLARE_INTERRUPT(11);
-DECLARE_INTERRUPT(12);
-DECLARE_INTERRUPT(13);
-DECLARE_INTERRUPT(14);
-DECLARE_INTERRUPT(15);
-
void __attribute__ ((regparm(0))) default_isr(void);
asm ("default_isr: iret\n");
-void disable_irq(int irq)
-{
- if (irq >= MAX_IRQ) {
- return;
- }
- irq_table[irq].status |= IRQ_DISABLED;
-
-}
-
-void enable_irq(int irq)
-{
- if (irq >= MAX_IRQ) {
- return;
- }
- irq_table[irq].status &= ~IRQ_DISABLED;
-}
-
-/* masks one specific IRQ in the PIC */
-static void unmask_irq(int irq)
-{
- int imr_port;
-
- if (irq >= MAX_IRQ) {
- return;
- }
- if (irq > 7) {
- imr_port = SLAVE_PIC + IMR;
- } else {
- imr_port = MASTER_PIC + IMR;
- }
-
- outb(inb(imr_port)&~(1<<(irq&7)), imr_port);
-}
-
-
-/* unmasks one specific IRQ in the PIC */
-static void mask_irq(int irq)
-{
- int imr_port;
-
- if (irq >= MAX_IRQ) {
- return;
- }
- if (irq > 7) {
- imr_port = SLAVE_PIC + IMR;
- } else {
- imr_port = MASTER_PIC + IMR;
- }
-
- outb(inb(imr_port)|(1<<(irq&7)), imr_port);
-}
-
-
-/* issue a Specific End Of Interrupt instruciton */
-static void specific_eoi(int irq)
-{
- /* If it is on the slave PIC this have to be performed on
- * both the master and the slave PICs */
- if (irq > 7) {
- outb(OCW2_SEOI|(irq&7), SLAVE_PIC + OCW2);
- irq = SEOI_IR2; /* also do IR2 on master */
- }
- outb(OCW2_SEOI|irq, MASTER_PIC + OCW2);
-}
-
-void __attribute__ ((regparm(0))) do_irq(int irq)
-{
-
- mask_irq(irq);
-
- if (irq_table[irq].status & IRQ_DISABLED) {
- unmask_irq(irq);
- specific_eoi(irq);
- return;
- }
-
-
- if (NULL != irq_table[irq].handler) {
- irq_handler_t *handler;
- for (handler = irq_table[irq].handler;
- NULL!= handler; handler = handler->next) {
- handler->isr_func(handler->isr_data);
- }
- } else {
- if ((irq & 7) != 7) {
- printf("Spurious irq %d\n", irq);
- }
- }
- unmask_irq(irq);
- specific_eoi(irq);
-}
-
-
-void __attribute__ ((regparm(0))) unknown_exception_entry(int cause, int ip, int seg)
-{
- printf("Unknown Exception %d at %04x:%08x\n", cause, seg, ip);
-}
-
-void __attribute__ ((regparm(0))) divide_exception_entry(int cause, int ip, int seg)
-{
- printf("Divide Error (Division by zero) at %04x:%08x\n", seg, ip);
- while(1);
-}
-
-void __attribute__ ((regparm(0))) debug_exception_entry(int cause, int ip, int seg)
-{
- printf("Debug Interrupt (Single step) at %04x:%08x\n", seg, ip);
-}
-
-void __attribute__ ((regparm(0))) nmi_entry(int cause, int ip, int seg)
-{
- printf("NMI Interrupt at %04x:%08x\n", seg, ip);
-}
-
-void __attribute__ ((regparm(0))) invalid_instruction_entry(int cause, int ip, int seg)
-{
- printf("Invalid Instruction at %04x:%08x\n", seg, ip);
- while(1);
-}
-
-void __attribute__ ((regparm(0))) double_fault_entry(int cause, int ip, int seg)
-{
- printf("Double fault at %04x:%08x\n", seg, ip);
- while(1);
-}
-
-void __attribute__ ((regparm(0))) invalid_tss_exception_entry(int cause, int ip, int seg)
-{
- printf("Invalid TSS at %04x:%08x\n", seg, ip);
-}
-
-void __attribute__ ((regparm(0))) seg_fault_entry(int cause, int ip, int seg)
-{
- printf("Segmentation fault at %04x:%08x\n", seg, ip);
- while(1);
-}
-
-void __attribute__ ((regparm(0))) stack_fault_entry(int cause, int ip, int seg)
-{
- printf("Stack fault at %04x:%08x\n", seg, ip);
- while(1);
-}
-
-void __attribute__ ((regparm(0))) gpf_entry(int cause, int ip, int seg)
-{
- printf("General protection fault at %04x:%08x\n", seg, ip);
-}
-
-void __attribute__ ((regparm(0))) page_fault_entry(int cause, int ip, int seg)
-{
- printf("Page fault at %04x:%08x\n", seg, ip);
- while(1);
-}
-
-void __attribute__ ((regparm(0))) fp_exception_entry(int cause, int ip, int seg)
-{
- printf("Floating point exception at %04x:%08x\n", seg, ip);
-}
-
-void __attribute__ ((regparm(0))) alignment_check_entry(int cause, int ip, int seg)
-{
- printf("Alignment check at %04x:%08x\n", seg, ip);
-}
-
-void __attribute__ ((regparm(0))) machine_check_entry(int cause, int ip, int seg)
-{
- printf("Machine check exception at %04x:%08x\n", seg, ip);
-}
-
-
-void irq_install_handler(int ino, interrupt_handler_t *func, void *pdata)
-{
- int status;
-
- if (ino>MAX_IRQ) {
- return;
- }
-
- if (NULL != irq_table[ino].handler) {
- return;
- }
-
- status = disable_interrupts();
- irq_table[ino].handler = malloc(sizeof(irq_handler_t));
- if (NULL == irq_table[ino].handler) {
- return;
- }
-
- memset(irq_table[ino].handler, 0, sizeof(irq_handler_t));
-
- irq_table[ino].handler->isr_func = func;
- irq_table[ino].handler->isr_data = pdata;
- if (status) {
- enable_interrupts();
- }
-
- unmask_irq(ino);
-
- return;
-}
-
-void irq_free_handler(int ino)
-{
- int status;
- if (ino>MAX_IRQ) {
- return;
- }
-
- status = disable_interrupts();
- mask_irq(ino);
- if (NULL == irq_table[ino].handler) {
- return;
- }
- free(irq_table[ino].handler);
- irq_table[ino].handler=NULL;
- if (status) {
- enable_interrupts();
- }
- return;
-}
-
-
asm ("idt_ptr:\n"
".word 0x800\n" /* size of the table 8*256 bytes */
".long idt\n" /* offset */
".word 0x18\n");/* data segment */
-void set_vector(int intnum, void *routine)
+void set_vector(u8 intnum, void *routine)
{
- idt[intnum].base_high = (u16)((u32)(routine)>>16);
- idt[intnum].base_low = (u16)((u32)(routine)&0xffff);
+ idt[intnum].base_high = (u16)((u32)(routine + gd->reloc_off) >> 16);
+ idt[intnum].base_low = (u16)((u32)(routine + gd->reloc_off) & 0xffff);
}
-int interrupt_init(void)
+int cpu_init_interrupts(void)
{
int i;
/* Just in case... */
disable_interrupts();
- /* Initialize the IDT and stuff */
-
-
- memset(irq_table, 0, sizeof(irq_table));
-
/* Setup the IDT */
for (i=0;i<256;i++) {
idt[i].access = 0x8e;
@@ -406,89 +75,6 @@ int interrupt_init(void)
asm ("cs lidt idt_ptr\n");
- /* Setup exceptions */
- set_vector(0x00, exp_0);
- set_vector(0x01, exp_1);
- set_vector(0x02, exp_2);
- set_vector(0x03, exp_3);
- set_vector(0x04, exp_4);
- set_vector(0x05, exp_5);
- set_vector(0x06, exp_6);
- set_vector(0x07, exp_7);
- set_vector(0x08, exp_8);
- set_vector(0x09, exp_9);
- set_vector(0x0a, exp_10);
- set_vector(0x0b, exp_11);
- set_vector(0x0c, exp_12);
- set_vector(0x0d, exp_13);
- set_vector(0x0e, exp_14);
- set_vector(0x0f, exp_15);
- set_vector(0x10, exp_16);
- set_vector(0x11, exp_17);
- set_vector(0x12, exp_18);
- set_vector(0x13, exp_19);
- set_vector(0x14, exp_20);
- set_vector(0x15, exp_21);
- set_vector(0x16, exp_22);
- set_vector(0x17, exp_23);
- set_vector(0x18, exp_24);
- set_vector(0x19, exp_25);
- set_vector(0x1a, exp_26);
- set_vector(0x1b, exp_27);
- set_vector(0x1c, exp_28);
- set_vector(0x1d, exp_29);
- set_vector(0x1e, exp_30);
- set_vector(0x1f, exp_31);
-
-
- /* Setup interrupts */
- set_vector(0x20, irq_0);
- set_vector(0x21, irq_1);
- set_vector(0x23, irq_3);
- set_vector(0x24, irq_4);
- set_vector(0x25, irq_5);
- set_vector(0x26, irq_6);
- set_vector(0x27, irq_7);
- set_vector(0x28, irq_8);
- set_vector(0x29, irq_9);
- set_vector(0x2a, irq_10);
- set_vector(0x2b, irq_11);
- set_vector(0x2c, irq_12);
- set_vector(0x2d, irq_13);
- set_vector(0x2e, irq_14);
- set_vector(0x2f, irq_15);
- /* vectors 0x30-0x3f are reserved for irq 16-31 */
-
-
- /* Mask all interrupts */
- outb(0xff, MASTER_PIC + IMR);
- outb(0xff, SLAVE_PIC + IMR);
-
- /* Master PIC */
- outb(ICW1_SEL|ICW1_EICW4, MASTER_PIC + ICW1);
- outb(0x20, MASTER_PIC + ICW2); /* Place master PIC interrupts at INT20 */
- outb(IR2, MASTER_PIC + ICW3); /* ICW3, One slevc PIC is present */
- outb(ICW4_PM, MASTER_PIC + ICW4);
-
- for (i=0;i<8;i++) {
- outb(OCW2_SEOI|i, MASTER_PIC + OCW2);
- }
-
- /* Slave PIC */
- outb(ICW1_SEL|ICW1_EICW4, SLAVE_PIC + ICW1);
- outb(0x28, SLAVE_PIC + ICW2); /* Place slave PIC interrupts at INT28 */
- outb(0x02, SLAVE_PIC + ICW3); /* Slave ID */
- outb(ICW4_PM, SLAVE_PIC + ICW4);
-
- for (i=0;i<8;i++) {
- outb(OCW2_SEOI|i, SLAVE_PIC + OCW2);
- }
-
-
- /* enable cascade interrerupt */
- outb(0xfb, MASTER_PIC + IMR);
- outb(0xff, SLAVE_PIC + IMR);
-
/* It is now safe to enable interrupts */
enable_interrupts();
diff --git a/cpu/i386/sc520/Makefile b/cpu/i386/sc520/Makefile
index ddfec23..87835b2 100644
--- a/cpu/i386/sc520/Makefile
+++ b/cpu/i386/sc520/Makefile
@@ -32,6 +32,10 @@ include $(TOPDIR)/config.mk
LIB := $(obj)lib$(SOC).a
COBJS-$(CONFIG_SYS_SC520) += sc520.o
+COBJS-$(CONFIG_SYS_SC520_SSI) += sc520_ssi.o
+COBJS-$(CONFIG_SYS_SC520_TIMER) += sc520_timer.o
+COBJS-$(CONFIG_PCI) += sc520_pci.o
+
SOBJS-$(CONFIG_SYS_SC520) += sc520_asm.o
SRCS := $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
diff --git a/cpu/i386/sc520/sc520.c b/cpu/i386/sc520/sc520.c
index b958f8d..ae3b500 100644
--- a/cpu/i386/sc520/sc520.c
+++ b/cpu/i386/sc520/sc520.c
@@ -24,15 +24,8 @@
/* stuff specific for the sc520,
* but idependent of implementation */
-#include <config.h>
#include <common.h>
-#include <config.h>
-#include <pci.h>
-#ifdef CONFIG_SC520_SSI
-#include <asm/ic/ssi.h>
-#endif
#include <asm/io.h>
-#include <asm/pci.h>
#include <asm/ic/sc520.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -50,13 +43,6 @@ DECLARE_GLOBAL_DATA_PTR;
*
* void init_sc520(void)
* unsigned long init_sc520_dram(void)
- * void pci_sc520_init(struct pci_controller *hose)
- *
- * void reset_timer(void)
- * ulong get_timer(ulong base)
- * void set_timer(ulong t)
- * void udelay(unsigned long usec)
- *
*/
static u32 mmcr_base= 0xfffef000;
@@ -241,270 +227,7 @@ unsigned long init_sc520_dram(void)
return dram_present;
}
-
-#ifdef CONFIG_PCI
-
-
-static struct {
- u8 priority;
- u16 level_reg;
- u8 level_bit;
-} sc520_irq[] = {
- { SC520_IRQ0, SC520_MPICMODE, 0x01 },
- { SC520_IRQ1, SC520_MPICMODE, 0x02 },
- { SC520_IRQ2, SC520_SL1PICMODE, 0x02 },
- { SC520_IRQ3, SC520_MPICMODE, 0x08 },
- { SC520_IRQ4, SC520_MPICMODE, 0x10 },
- { SC520_IRQ5, SC520_MPICMODE, 0x20 },
- { SC520_IRQ6, SC520_MPICMODE, 0x40 },
- { SC520_IRQ7, SC520_MPICMODE, 0x80 },
-
- { SC520_IRQ8, SC520_SL1PICMODE, 0x01 },
- { SC520_IRQ9, SC520_SL1PICMODE, 0x02 },
- { SC520_IRQ10, SC520_SL1PICMODE, 0x04 },
- { SC520_IRQ11, SC520_SL1PICMODE, 0x08 },
- { SC520_IRQ12, SC520_SL1PICMODE, 0x10 },
- { SC520_IRQ13, SC520_SL1PICMODE, 0x20 },
- { SC520_IRQ14, SC520_SL1PICMODE, 0x40 },
- { SC520_IRQ15, SC520_SL1PICMODE, 0x80 }
-};
-
-
-/* The interrupt used for PCI INTA-INTD */
-int sc520_pci_ints[15] = {
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1
-};
-
-/* utility function to configure a pci interrupt */
-int pci_sc520_set_irq(int pci_pin, int irq)
-{
- int i;
-
-# if 1
- printf("set_irq(): map INT%c to IRQ%d\n", pci_pin + 'A', irq);
-#endif
- if (irq < 0 || irq > 15) {
- return -1; /* illegal irq */
- }
-
- if (pci_pin < 0 || pci_pin > 15) {
- return -1; /* illegal pci int pin */
- }
-
- /* first disable any non-pci interrupt source that use
- * this level */
- for (i=SC520_GPTMR0MAP;i<=SC520_GP10IMAP;i++) {
- if (i>=SC520_PCIINTAMAP&&i<=SC520_PCIINTDMAP) {
- continue;
- }
- if (read_mmcr_byte(i) == sc520_irq[irq].priority) {
- write_mmcr_byte(i, SC520_IRQ_DISABLED);
- }
- }
-
- /* Set the trigger to level */
- write_mmcr_byte(sc520_irq[irq].level_reg,
- read_mmcr_byte(sc520_irq[irq].level_reg) | sc520_irq[irq].level_bit);
-
-
- if (pci_pin < 4) {
- /* PCI INTA-INTD */
- /* route the interrupt */
- write_mmcr_byte(SC520_PCIINTAMAP + pci_pin, sc520_irq[irq].priority);
-
-
- } else {
- /* GPIRQ0-GPIRQ10 used for additional PCI INTS */
- write_mmcr_byte(SC520_GP0IMAP + pci_pin - 4, sc520_irq[irq].priority);
-
- /* also set the polarity in this case */
- write_mmcr_word(SC520_INTPINPOL,
- read_mmcr_word(SC520_INTPINPOL) | (1 << (pci_pin-4)));
-
- }
-
- /* register the pin */
- sc520_pci_ints[pci_pin] = irq;
-
-
- return 0; /* OK */
-}
-
-void pci_sc520_init(struct pci_controller *hose)
-{
- hose->first_busno = 0;
- hose->last_busno = 0xff;
-
- /* System memory space */
- pci_set_region(hose->regions + 0,
- SC520_PCI_MEMORY_BUS,
- SC520_PCI_MEMORY_PHYS,
- SC520_PCI_MEMORY_SIZE,
- PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
-
- /* PCI memory space */
- pci_set_region(hose->regions + 1,
- SC520_PCI_MEM_BUS,
- SC520_PCI_MEM_PHYS,
- SC520_PCI_MEM_SIZE,
- PCI_REGION_MEM);
-
- /* ISA/PCI memory space */
- pci_set_region(hose->regions + 2,
- SC520_ISA_MEM_BUS,
- SC520_ISA_MEM_PHYS,
- SC520_ISA_MEM_SIZE,
- PCI_REGION_MEM);
-
- /* PCI I/O space */
- pci_set_region(hose->regions + 3,
- SC520_PCI_IO_BUS,
- SC520_PCI_IO_PHYS,
- SC520_PCI_IO_SIZE,
- PCI_REGION_IO);
-
- /* ISA/PCI I/O space */
- pci_set_region(hose->regions + 4,
- SC520_ISA_IO_BUS,
- SC520_ISA_IO_PHYS,
- SC520_ISA_IO_SIZE,
- PCI_REGION_IO);
-
- hose->region_count = 5;
-
- pci_setup_type1(hose,
- SC520_REG_ADDR,
- SC520_REG_DATA);
-
- pci_register_hose(hose);
-
- hose->last_busno = pci_hose_scan(hose);
-
- /* enable target memory acceses on host brige */
- pci_write_config_word(0, PCI_COMMAND,
- PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
-
-}
-
-
-#endif
-
-#ifdef CONFIG_SYS_TIMER_SC520
-
-
-void reset_timer(void)
-{
- write_mmcr_word(SC520_GPTMR0CNT, 0);
- write_mmcr_word(SC520_GPTMR0CTL, 0x6001);
-
-}
-
-ulong get_timer(ulong base)
-{
- /* fixme: 30 or 33 */
- return read_mmcr_word(SC520_GPTMR0CNT) / 33;
-}
-
-void set_timer(ulong t)
-{
- /* FixMe: use two cascade coupled timers */
- write_mmcr_word(SC520_GPTMR0CTL, 0x4001);
- write_mmcr_word(SC520_GPTMR0CNT, t*33);
- write_mmcr_word(SC520_GPTMR0CTL, 0x6001);
-}
-
-
-void udelay(unsigned long usec)
-{
- int m=0;
- long u;
-
- read_mmcr_word(SC520_SWTMRMILLI);
- read_mmcr_word(SC520_SWTMRMICRO);
-
-#if 0
- /* do not enable this line, udelay is used in the serial driver -> recursion */
- printf("udelay: %ld m.u %d.%d tm.tu %d.%d\n", usec, m, u, tm, tu);
-#endif
- while (1) {
-
- m += read_mmcr_word(SC520_SWTMRMILLI);
- u = read_mmcr_word(SC520_SWTMRMICRO) + (m * 1000);
-
- if (usec <= u) {
- break;
- }
- }
-}
-
-#endif
-
-int ssi_set_interface(int freq, int lsb_first, int inv_clock, int inv_phase)
-{
- u8 temp=0;
-
- if (freq >= 8192) {
- temp |= CTL_CLK_SEL_4;
- } else if (freq >= 4096) {
- temp |= CTL_CLK_SEL_8;
- } else if (freq >= 2048) {
- temp |= CTL_CLK_SEL_16;
- } else if (freq >= 1024) {
- temp |= CTL_CLK_SEL_32;
- } else if (freq >= 512) {
- temp |= CTL_CLK_SEL_64;
- } else if (freq >= 256) {
- temp |= CTL_CLK_SEL_128;
- } else if (freq >= 128) {
- temp |= CTL_CLK_SEL_256;
- } else {
- temp |= CTL_CLK_SEL_512;
- }
-
- if (!lsb_first) {
- temp |= MSBF_ENB;
- }
-
- if (inv_clock) {
- temp |= CLK_INV_ENB;
- }
-
- if (inv_phase) {
- temp |= PHS_INV_ENB;
- }
-
- write_mmcr_byte(SC520_SSICTL, temp);
-
- return 0;
-}
-
-u8 ssi_txrx_byte(u8 data)
-{
- write_mmcr_byte(SC520_SSIXMIT, data);
- while ((read_mmcr_byte(SC520_SSISTA)) & SSISTA_BSY);
- write_mmcr_byte(SC520_SSICMD, SSICMD_CMD_SEL_XMITRCV);
- while ((read_mmcr_byte(SC520_SSISTA)) & SSISTA_BSY);
- return read_mmcr_byte(SC520_SSIRCV);
-}
-
-
-void ssi_tx_byte(u8 data)
-{
- write_mmcr_byte(SC520_SSIXMIT, data);
- while ((read_mmcr_byte(SC520_SSISTA)) & SSISTA_BSY);
- write_mmcr_byte(SC520_SSICMD, SSICMD_CMD_SEL_XMIT);
-}
-
-u8 ssi_rx_byte(void)
-{
- while ((read_mmcr_byte(SC520_SSISTA)) & SSISTA_BSY);
- write_mmcr_byte(SC520_SSICMD, SSICMD_CMD_SEL_RCV);
- while ((read_mmcr_byte(SC520_SSISTA)) & SSISTA_BSY);
- return read_mmcr_byte(SC520_SSIRCV);
-}
-
-#ifdef CONFIG_SYS_RESET_SC520
+#ifdef CONFIG_SYS_SC520_RESET
void reset_cpu(ulong addr)
{
printf("Resetting using SC520 MMCR\n");
diff --git a/cpu/i386/sc520/sc520_pci.c b/cpu/i386/sc520/sc520_pci.c
new file mode 100644
index 0000000..38b837e
--- /dev/null
+++ b/cpu/i386/sc520/sc520_pci.c
@@ -0,0 +1,171 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB <daniel@omicron.se>.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* stuff specific for the sc520, but independent of implementation */
+
+#include <common.h>
+#include <pci.h>
+#include <asm/pci.h>
+#include <asm/ic/sc520.h>
+
+static struct {
+ u8 priority;
+ u16 level_reg;
+ u8 level_bit;
+} sc520_irq[] = {
+ { SC520_IRQ0, SC520_MPICMODE, 0x01 },
+ { SC520_IRQ1, SC520_MPICMODE, 0x02 },
+ { SC520_IRQ2, SC520_SL1PICMODE, 0x02 },
+ { SC520_IRQ3, SC520_MPICMODE, 0x08 },
+ { SC520_IRQ4, SC520_MPICMODE, 0x10 },
+ { SC520_IRQ5, SC520_MPICMODE, 0x20 },
+ { SC520_IRQ6, SC520_MPICMODE, 0x40 },
+ { SC520_IRQ7, SC520_MPICMODE, 0x80 },
+
+ { SC520_IRQ8, SC520_SL1PICMODE, 0x01 },
+ { SC520_IRQ9, SC520_SL1PICMODE, 0x02 },
+ { SC520_IRQ10, SC520_SL1PICMODE, 0x04 },
+ { SC520_IRQ11, SC520_SL1PICMODE, 0x08 },
+ { SC520_IRQ12, SC520_SL1PICMODE, 0x10 },
+ { SC520_IRQ13, SC520_SL1PICMODE, 0x20 },
+ { SC520_IRQ14, SC520_SL1PICMODE, 0x40 },
+ { SC520_IRQ15, SC520_SL1PICMODE, 0x80 }
+};
+
+
+/* The interrupt used for PCI INTA-INTD */
+int sc520_pci_ints[15] = {
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1
+};
+
+/* utility function to configure a pci interrupt */
+int pci_sc520_set_irq(int pci_pin, int irq)
+{
+ int i;
+
+# if 1
+ printf("set_irq(): map INT%c to IRQ%d\n", pci_pin + 'A', irq);
+#endif
+ if (irq < 0 || irq > 15) {
+ return -1; /* illegal irq */
+ }
+
+ if (pci_pin < 0 || pci_pin > 15) {
+ return -1; /* illegal pci int pin */
+ }
+
+ /* first disable any non-pci interrupt source that use
+ * this level */
+ for (i=SC520_GPTMR0MAP;i<=SC520_GP10IMAP;i++) {
+ if (i>=SC520_PCIINTAMAP&&i<=SC520_PCIINTDMAP) {
+ continue;
+ }
+ if (read_mmcr_byte(i) == sc520_irq[irq].priority) {
+ write_mmcr_byte(i, SC520_IRQ_DISABLED);
+ }
+ }
+
+ /* Set the trigger to level */
+ write_mmcr_byte(sc520_irq[irq].level_reg,
+ read_mmcr_byte(sc520_irq[irq].level_reg) | sc520_irq[irq].level_bit);
+
+
+ if (pci_pin < 4) {
+ /* PCI INTA-INTD */
+ /* route the interrupt */
+ write_mmcr_byte(SC520_PCIINTAMAP + pci_pin, sc520_irq[irq].priority);
+
+
+ } else {
+ /* GPIRQ0-GPIRQ10 used for additional PCI INTS */
+ write_mmcr_byte(SC520_GP0IMAP + pci_pin - 4, sc520_irq[irq].priority);
+
+ /* also set the polarity in this case */
+ write_mmcr_word(SC520_INTPINPOL,
+ read_mmcr_word(SC520_INTPINPOL) | (1 << (pci_pin-4)));
+
+ }
+
+ /* register the pin */
+ sc520_pci_ints[pci_pin] = irq;
+
+
+ return 0; /* OK */
+}
+
+void pci_sc520_init(struct pci_controller *hose)
+{
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+
+ /* System memory space */
+ pci_set_region(hose->regions + 0,
+ SC520_PCI_MEMORY_BUS,
+ SC520_PCI_MEMORY_PHYS,
+ SC520_PCI_MEMORY_SIZE,
+ PCI_REGION_MEM | PCI_REGION_MEMORY);
+
+ /* PCI memory space */
+ pci_set_region(hose->regions + 1,
+ SC520_PCI_MEM_BUS,
+ SC520_PCI_MEM_PHYS,
+ SC520_PCI_MEM_SIZE,
+ PCI_REGION_MEM);
+
+ /* ISA/PCI memory space */
+ pci_set_region(hose->regions + 2,
+ SC520_ISA_MEM_BUS,
+ SC520_ISA_MEM_PHYS,
+ SC520_ISA_MEM_SIZE,
+ PCI_REGION_MEM);
+
+ /* PCI I/O space */
+ pci_set_region(hose->regions + 3,
+ SC520_PCI_IO_BUS,
+ SC520_PCI_IO_PHYS,
+ SC520_PCI_IO_SIZE,
+ PCI_REGION_IO);
+
+ /* ISA/PCI I/O space */
+ pci_set_region(hose->regions + 4,
+ SC520_ISA_IO_BUS,
+ SC520_ISA_IO_PHYS,
+ SC520_ISA_IO_SIZE,
+ PCI_REGION_IO);
+
+ hose->region_count = 5;
+
+ pci_setup_type1(hose,
+ SC520_REG_ADDR,
+ SC520_REG_DATA);
+
+ pci_register_hose(hose);
+
+ hose->last_busno = pci_hose_scan(hose);
+
+ /* enable target memory acceses on host brige */
+ pci_write_config_word(0, PCI_COMMAND,
+ PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+
+}
diff --git a/cpu/i386/sc520/sc520_ssi.c b/cpu/i386/sc520/sc520_ssi.c
new file mode 100644
index 0000000..dd667ca
--- /dev/null
+++ b/cpu/i386/sc520/sc520_ssi.c
@@ -0,0 +1,92 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB <daniel@omicron.se>.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* stuff specific for the sc520, but independent of implementation */
+
+#include <common.h>
+#include <asm/ic/ssi.h>
+#include <asm/ic/sc520.h>
+
+int ssi_set_interface(int freq, int lsb_first, int inv_clock, int inv_phase)
+{
+ u8 temp=0;
+
+ if (freq >= 8192) {
+ temp |= CTL_CLK_SEL_4;
+ } else if (freq >= 4096) {
+ temp |= CTL_CLK_SEL_8;
+ } else if (freq >= 2048) {
+ temp |= CTL_CLK_SEL_16;
+ } else if (freq >= 1024) {
+ temp |= CTL_CLK_SEL_32;
+ } else if (freq >= 512) {
+ temp |= CTL_CLK_SEL_64;
+ } else if (freq >= 256) {
+ temp |= CTL_CLK_SEL_128;
+ } else if (freq >= 128) {
+ temp |= CTL_CLK_SEL_256;
+ } else {
+ temp |= CTL_CLK_SEL_512;
+ }
+
+ if (!lsb_first) {
+ temp |= MSBF_ENB;
+ }
+
+ if (inv_clock) {
+ temp |= CLK_INV_ENB;
+ }
+
+ if (inv_phase) {
+ temp |= PHS_INV_ENB;
+ }
+
+ write_mmcr_byte(SC520_SSICTL, temp);
+
+ return 0;
+}
+
+u8 ssi_txrx_byte(u8 data)
+{
+ write_mmcr_byte(SC520_SSIXMIT, data);
+ while ((read_mmcr_byte(SC520_SSISTA)) & SSISTA_BSY);
+ write_mmcr_byte(SC520_SSICMD, SSICMD_CMD_SEL_XMITRCV);
+ while ((read_mmcr_byte(SC520_SSISTA)) & SSISTA_BSY);
+ return read_mmcr_byte(SC520_SSIRCV);
+}
+
+
+void ssi_tx_byte(u8 data)
+{
+ write_mmcr_byte(SC520_SSIXMIT, data);
+ while ((read_mmcr_byte(SC520_SSISTA)) & SSISTA_BSY);
+ write_mmcr_byte(SC520_SSICMD, SSICMD_CMD_SEL_XMIT);
+}
+
+u8 ssi_rx_byte(void)
+{
+ while ((read_mmcr_byte(SC520_SSISTA)) & SSISTA_BSY);
+ write_mmcr_byte(SC520_SSICMD, SSICMD_CMD_SEL_RCV);
+ while ((read_mmcr_byte(SC520_SSISTA)) & SSISTA_BSY);
+ return read_mmcr_byte(SC520_SSIRCV);
+}
diff --git a/cpu/i386/sc520/sc520_timer.c b/cpu/i386/sc520/sc520_timer.c
new file mode 100644
index 0000000..2cb8656
--- /dev/null
+++ b/cpu/i386/sc520/sc520_timer.c
@@ -0,0 +1,82 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB <daniel@omicron.se>.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* stuff specific for the sc520, but independent of implementation */
+
+#include <common.h>
+#include <asm/interrupt.h>
+#include <asm/ic/sc520.h>
+
+void sc520_timer_isr(void)
+{
+ /* Ack the GP Timer Interrupt */
+ write_mmcr_byte (SC520_GPTMRSTA, 0x02);
+}
+
+int timer_init(void)
+{
+ /* Map GP Timer 1 to Master PIC IR0 */
+ write_mmcr_byte (SC520_GPTMR1MAP, 0x01);
+
+ /* Disable GP Timers 1 & 2 - Allow configuration writes */
+ write_mmcr_word (SC520_GPTMR1CTL, 0x4000);
+ write_mmcr_word (SC520_GPTMR2CTL, 0x4000);
+
+ /* Reset GP Timers 1 & 2 */
+ write_mmcr_word (SC520_GPTMR1CNT, 0x0000);
+ write_mmcr_word (SC520_GPTMR2CNT, 0x0000);
+
+ /* Setup GP Timer 2 as a 100kHz (10us) prescaler */
+ write_mmcr_word (SC520_GPTMR2MAXCMPA, 83);
+ write_mmcr_word (SC520_GPTMR2CTL, 0xc001);
+
+ /* Setup GP Timer 1 as a 1000 Hz (1ms) interrupt generator */
+ write_mmcr_word (SC520_GPTMR1MAXCMPA, 100);
+ write_mmcr_word (SC520_GPTMR1CTL, 0xe009);
+
+ /* Clear the GP Timers status register */
+ write_mmcr_byte (SC520_GPTMRSTA, 0x07);
+
+ /* Register the SC520 specific timer interrupt handler */
+ register_timer_isr (sc520_timer_isr);
+
+ /* Install interrupt handler for GP Timer 1 */
+ irq_install_handler (0, timer_isr, NULL);
+ unmask_irq (0);
+
+ return 0;
+}
+
+void udelay(unsigned long usec)
+{
+ int m = 0;
+ long u;
+
+ read_mmcr_word (SC520_SWTMRMILLI);
+ read_mmcr_word (SC520_SWTMRMICRO);
+
+ do {
+ m += read_mmcr_word (SC520_SWTMRMILLI);
+ u = read_mmcr_word (SC520_SWTMRMICRO) + (m * 1000);
+ } while (u < usec);
+}
diff --git a/cpu/i386/start.S b/cpu/i386/start.S
index b6175b1..59089ef 100644
--- a/cpu/i386/start.S
+++ b/cpu/i386/start.S
@@ -173,7 +173,41 @@ bss_fail:
jmp die
bss_ok:
+#ifndef CONFIG_SKIP_RELOCATE_UBOOT
+ /* indicate progress */
+ movw $0x06, %ax
+ movl $.progress6, %ebp
+ jmp show_boot_progress_asm
+.progress6:
+
+ /* copy text section to ram, size must be 4-byte aligned */
+ movl $CONFIG_SYS_BL_START_RAM, %edi /* destination address */
+ movl $TEXT_BASE, %esi /* source address */
+ movl $_i386boot_text_size, %ecx /* number of bytes to copy */
+ movl %ecx, %eax
+ andl $3, %eax
+ jz text_copy /* Already 4-byte aligned */
+ subl $4, %eax /* Add extra bytes to size */
+ addl %eax, %ecx
+text_copy:
+ shrl $2, %ecx /* copy 4 byte each time */
+ cld
+ cmpl $0, %ecx
+ je text_ok
+text_segment:
+ movsl
+ loop text_segment
+ jmp text_ok
+text_fail:
+ /* indicate (lack of) progress */
+ movw $0x86, %ax
+ movl $.progress5a, %ebp
+ jmp show_boot_progress_asm
+.progress5a:
+ jmp die
+text_ok:
+#endif
wbinvd
@@ -183,7 +217,14 @@ bss_ok:
jmp show_boot_progress_asm
.progress4:
+#ifndef CONFIG_SKIP_RELOCATE_UBOOT
+ /* Jump to the RAM copy of start_i386boot */
+ movl $start_i386boot, %ebp
+ addl $(CONFIG_SYS_BL_START_RAM - TEXT_BASE), %ebp
+ call *%ebp /* Enter, U-boot! */
+#else
call start_i386boot /* Enter, U-boot! */
+#endif
/* indicate (lack of) progress */
movw $0x85, %ax
diff --git a/cpu/i386/timer.c b/cpu/i386/timer.c
deleted file mode 100644
index 46db23f..0000000
--- a/cpu/i386/timer.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * (C) Copyright 2002
- * Daniel Engström, Omicron Ceti AB, daniel@omicron.se.
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#include <common.h>
-#include <asm/io.h>
-#include <asm/i8254.h>
-#include <asm/ibmpc.h>
-
-
-static volatile unsigned long system_ticks;
-static int timer_init_done =0;
-
-static void timer_isr(void *unused)
-{
- system_ticks++;
-}
-
-unsigned long get_system_ticks(void)
-{
- return system_ticks;
-}
-
-#define TIMER0_VALUE 0x04aa /* 1kHz 1.9318MHz / 1000 */
-#define TIMER2_VALUE 0x0a8e /* 440Hz */
-
-int timer_init(void)
-{
- system_ticks = 0;
-
- irq_install_handler(0, timer_isr, NULL);
-
- /* initialize timer 0 and 2
- *
- * Timer 0 is used to increment system_tick 1000 times/sec
- * Timer 1 was used for DRAM refresh in early PC's
- * Timer 2 is used to drive the speaker
- * (to stasrt a beep: write 3 to port 0x61,
- * to stop it again: write 0)
- */
-
- outb(PIT_CMD_CTR0|PIT_CMD_BOTH|PIT_CMD_MODE2, PIT_BASE + PIT_COMMAND);
- outb(TIMER0_VALUE&0xff, PIT_BASE + PIT_T0);
- outb(TIMER0_VALUE>>8, PIT_BASE + PIT_T0);
-
- outb(PIT_CMD_CTR2|PIT_CMD_BOTH|PIT_CMD_MODE3, PIT_BASE + PIT_COMMAND);
- outb(TIMER2_VALUE&0xff, PIT_BASE + PIT_T2);
- outb(TIMER2_VALUE>>8, PIT_BASE + PIT_T2);
-
- timer_init_done = 1;
-
- return 0;
-}
-
-
-#ifdef CONFIG_SYS_TIMER_GENERIC
-
-/* the unit for these is CONFIG_SYS_HZ */
-
-/* FixMe: implement these */
-void reset_timer (void)
-{
- system_ticks = 0;
-}
-
-ulong get_timer (ulong base)
-{
- return (system_ticks - base);
-}
-
-void set_timer (ulong t)
-{
- system_ticks = t;
-}
-
-static u16 read_pit(void)
-{
- u8 low;
- outb(PIT_CMD_LATCH, PIT_BASE + PIT_COMMAND);
- low = inb(PIT_BASE + PIT_T0);
- return ((inb(PIT_BASE + PIT_T0) << 8) | low);
-}
-
-/* this is not very exact */
-void udelay (unsigned long usec)
-{
- int counter;
- int wraps;
-
- if (!timer_init_done) {
- return;
- }
- counter = read_pit();
- wraps = usec/1000;
- usec = usec%1000;
-
- usec*=1194;
- usec/=1000;
- usec+=counter;
- if (usec > 1194) {
- usec-=1194;
- wraps++;
- }
-
- while (1) {
- int new_count = read_pit();
-
- if (((new_count < usec) && !wraps) || wraps < 0) {
- break;
- }
-
- if (new_count > counter) {
- wraps--;
- }
- counter = new_count;
- }
-
-}
-
-#if 0
-/* this is a version with debug output */
-void _udelay (unsigned long usec)
-{
- int counter;
- int wraps;
-
- int usec1, usec2, usec3;
- int wraps1, wraps2, wraps3, wraps4;
- int ctr1, ctr2, ctr3, nct1, nct2;
- int i;
- usec1=usec;
- if (!timer_init_done) {
- return;
- }
- counter = read_pit();
- ctr1 = counter;
- wraps = usec/1000;
- usec = usec%1000;
-
- usec2 = usec;
- wraps1 = wraps;
-
- usec*=1194;
- usec/=1000;
- usec+=counter;
- if (usec > 1194) {
- usec-=1194;
- wraps++;
- }
-
- usec3 = usec;
- wraps2 = wraps;
-
- ctr2 = wraps3 = nct1 = 4711;
- ctr3 = wraps4 = nct2 = 4711;
- i=0;
- while (1) {
- int new_count = read_pit();
- i++;
- if ((new_count < usec && !wraps) || wraps < 0) {
- break;
- }
-
- if (new_count > counter) {
- wraps--;
- }
- if (ctr2==4711) {
- ctr2 = counter;
- wraps3 = wraps;
- nct1 = new_count;
- } else {
- ctr3 = counter;
- wraps4 = wraps;
- nct2 = new_count;
- }
-
- counter = new_count;
- }
-
- printf("udelay(%d)\n", usec1);
- printf("counter %d\n", ctr1);
- printf("1: wraps %d, usec %d\n", wraps1, usec2);
- printf("2: wraps %d, usec %d\n", wraps2, usec3);
- printf("new_count[0] %d counter %d wraps %d\n", nct1, ctr2, wraps3);
- printf("new_count[%d] %d counter %d wraps %d\n", i, nct2, ctr3, wraps4);
-
- printf("%d %d %d %d %d\n",
- read_pit(), read_pit(), read_pit(),
- read_pit(), read_pit());
-}
-#endif
-#endif
diff --git a/cpu/ixp/npe/npe.c b/cpu/ixp/npe/npe.c
index 03e3bf7..2e68689 100644
--- a/cpu/ixp/npe/npe.c
+++ b/cpu/ixp/npe/npe.c
@@ -565,25 +565,19 @@ int npe_initialize(bd_t * bis)
struct eth_device *dev;
int eth_num = 0;
struct npe *p_npe = NULL;
+ uchar enetaddr[6];
for (eth_num = 0; eth_num < CONFIG_SYS_NPE_NUMS; eth_num++) {
/* See if we can actually bring up the interface, otherwise, skip it */
- switch (eth_num) {
- default: /* fall through */
- case 0:
- if (memcmp (bis->bi_enetaddr, "\0\0\0\0\0\0", 6) == 0) {
- continue;
- }
- break;
#ifdef CONFIG_HAS_ETH1
- case 1:
- if (memcmp (bis->bi_enet1addr, "\0\0\0\0\0\0", 6) == 0) {
+ if (eth_num == 1) {
+ if (!eth_getenv_enetaddr("eth1addr", enetaddr))
continue;
- }
- break;
+ } else
#endif
- }
+ if (!eth_getenv_enetaddr("ethaddr", enetaddr))
+ continue;
/* Allocate device structure */
dev = (struct eth_device *)malloc(sizeof(*dev));
@@ -603,22 +597,14 @@ int npe_initialize(bd_t * bis)
}
memset(p_npe, 0, sizeof(struct npe));
- switch (eth_num) {
- default: /* fall through */
- case 0:
- memcpy(dev->enetaddr, bis->bi_enetaddr, 6);
- p_npe->eth_id = 0;
- p_npe->phy_no = CONFIG_PHY_ADDR;
- break;
-
+ p_npe->eth_id = eth_num;
+ memcpy(dev->enetaddr, enetaddr, 6);
#ifdef CONFIG_HAS_ETH1
- case 1:
- memcpy(dev->enetaddr, bis->bi_enet1addr, 6);
- p_npe->eth_id = 1;
+ if (eth_num == 1)
p_npe->phy_no = CONFIG_PHY1_ADDR;
- break;
+ else
#endif
- }
+ p_npe->phy_no = CONFIG_PHY_ADDR;
sprintf(dev->name, "NPE%d", eth_num);
dev->priv = (void *)p_npe;
diff --git a/cpu/mpc512x/cpu.c b/cpu/mpc512x/cpu.c
index b9069b0..be532af 100644
--- a/cpu/mpc512x/cpu.c
+++ b/cpu/mpc512x/cpu.c
@@ -148,15 +148,17 @@ static void old_ft_cpu_setup(void *blob, bd_t *bd)
* avoid fixing up by path because that
* produces scary error messages
*/
+ uchar enetaddr[6];
/*
* old device trees have ethernet nodes with
* device_type = "network"
*/
+ eth_getenv_enetaddr("ethaddr", enetaddr);
do_fixup_by_prop(blob, "device_type", "network", 8,
- "local-mac-address", bd->bi_enetaddr, 6, 0);
+ "local-mac-address", enetaddr, 6, 0);
do_fixup_by_prop(blob, "device_type", "network", 8,
- "address", bd->bi_enetaddr, 6, 0);
+ "address", enetaddr, 6, 0);
/*
* old device trees have soc nodes with
* device_type = "soc"
diff --git a/cpu/mpc5xx/u-boot.lds b/cpu/mpc5xx/u-boot.lds
index bf52179..cb17ca5 100644
--- a/cpu/mpc5xx/u-boot.lds
+++ b/cpu/mpc5xx/u-boot.lds
@@ -65,10 +65,8 @@ SECTIONS
PROVIDE (etext = .);
.rodata :
{
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/cpu/mpc5xxx/cpu.c b/cpu/mpc5xxx/cpu.c
index 9c6ab76..f6258c7 100644
--- a/cpu/mpc5xxx/cpu.c
+++ b/cpu/mpc5xxx/cpu.c
@@ -28,6 +28,7 @@
#include <common.h>
#include <watchdog.h>
#include <command.h>
+#include <net.h>
#include <mpc5xxx.h>
#include <netdev.h>
#include <asm/io.h>
@@ -121,6 +122,7 @@ void ft_cpu_setup(void *blob, bd_t *bd)
int div = in_8((void*)CONFIG_SYS_MBAR + 0x204) & 0x0020 ? 8 : 4;
char * cpu_path = "/cpus/" OF_CPU;
#ifdef CONFIG_MPC5xxx_FEC
+ uchar enetaddr[6];
char * eth_path = "/" OF_SOC "/ethernet@3000";
#endif
@@ -131,8 +133,9 @@ void ft_cpu_setup(void *blob, bd_t *bd)
do_fixup_by_path_u32(blob, "/" OF_SOC, "system-frequency",
bd->bi_busfreq*div, 1);
#ifdef CONFIG_MPC5xxx_FEC
- do_fixup_by_path(blob, eth_path, "mac-address", bd->bi_enetaddr, 6, 0);
- do_fixup_by_path(blob, eth_path, "local-mac-address", bd->bi_enetaddr, 6, 0);
+ eth_getenv_enetaddr("ethaddr", enetaddr);
+ do_fixup_by_path(blob, eth_path, "mac-address", enetaddr, 6, 0);
+ do_fixup_by_path(blob, eth_path, "local-mac-address", enetaddr, 6, 0);
#endif
}
#endif
diff --git a/cpu/mpc5xxx/u-boot-customlayout.lds b/cpu/mpc5xxx/u-boot-customlayout.lds
index f6bb858..9563690 100644
--- a/cpu/mpc5xxx/u-boot-customlayout.lds
+++ b/cpu/mpc5xxx/u-boot-customlayout.lds
@@ -68,10 +68,8 @@ SECTIONS
*(.fixup)
*(.got1)
. = ALIGN(16);
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/cpu/mpc5xxx/u-boot.lds b/cpu/mpc5xxx/u-boot.lds
index 8d1fa60..a6d4ff3 100644
--- a/cpu/mpc5xxx/u-boot.lds
+++ b/cpu/mpc5xxx/u-boot.lds
@@ -57,10 +57,8 @@ SECTIONS
*(.fixup)
*(.got1)
. = ALIGN(16);
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/cpu/mpc8220/u-boot.lds b/cpu/mpc8220/u-boot.lds
index 2a12a69..436423c 100644
--- a/cpu/mpc8220/u-boot.lds
+++ b/cpu/mpc8220/u-boot.lds
@@ -57,10 +57,8 @@ SECTIONS
*(.fixup)
*(.got1)
. = ALIGN(16);
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/cpu/mpc824x/u-boot.lds b/cpu/mpc824x/u-boot.lds
index 8c7e135..46f7087 100644
--- a/cpu/mpc824x/u-boot.lds
+++ b/cpu/mpc824x/u-boot.lds
@@ -57,10 +57,8 @@ SECTIONS
*(.fixup)
*(.got1)
. = ALIGN(16);
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/cpu/mpc8260/ether_fcc.c b/cpu/mpc8260/ether_fcc.c
index 3ab57eb..5ac02a0 100644
--- a/cpu/mpc8260/ether_fcc.c
+++ b/cpu/mpc8260/ether_fcc.c
@@ -654,7 +654,7 @@ eth_loopback_test (void)
puts ("FCC Ethernet External loopback test\n");
- memcpy (NetOurEther, gd->bd->bi_enetaddr, 6);
+ eth_getenv_enetaddr("ethaddr", NetOurEther);
/*
* global initialisations for all FCC channels
@@ -841,7 +841,7 @@ eth_loopback_test (void)
* So, far we have only been given one Ethernet address. We use
* the same address for all channels
*/
-#define ea gd->bd->bi_enetaddr
+#define ea NetOurEther
fpp->fen_paddrh = (ea[5] << 8) + ea[4];
fpp->fen_paddrm = (ea[3] << 8) + ea[2];
fpp->fen_paddrl = (ea[1] << 8) + ea[0];
diff --git a/cpu/mpc8260/ether_scc.c b/cpu/mpc8260/ether_scc.c
index 3671ef1..432111d 100644
--- a/cpu/mpc8260/ether_scc.c
+++ b/cpu/mpc8260/ether_scc.c
@@ -199,6 +199,7 @@ static int sec_init(struct eth_device *dev, bd_t *bis)
volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
scc_enet_t *pram_ptr;
uint dpaddr;
+ uchar ea[6];
rxIdx = 0;
txIdx = 0;
@@ -261,11 +262,10 @@ static int sec_init(struct eth_device *dev, bd_t *bis)
pram_ptr->sen_gaddr3 = 0x0; /* Group Address Filter 3 (unused) */
pram_ptr->sen_gaddr4 = 0x0; /* Group Address Filter 4 (unused) */
-# define ea bis->bi_enetaddr
+ eth_getenv_enetaddr("ethaddr", ea);
pram_ptr->sen_paddrh = (ea[5] << 8) + ea[4];
pram_ptr->sen_paddrm = (ea[3] << 8) + ea[2];
pram_ptr->sen_paddrl = (ea[1] << 8) + ea[0];
-# undef ea
pram_ptr->sen_pper = 0x0; /* Persistence (unused) */
diff --git a/cpu/mpc8260/u-boot.lds b/cpu/mpc8260/u-boot.lds
index d65a939..b3a103d 100644
--- a/cpu/mpc8260/u-boot.lds
+++ b/cpu/mpc8260/u-boot.lds
@@ -57,10 +57,8 @@ SECTIONS
*(.fixup)
*(.got1)
. = ALIGN(16);
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/cpu/mpc83xx/u-boot.lds b/cpu/mpc83xx/u-boot.lds
index 3a08f64..7d57ee4 100644
--- a/cpu/mpc83xx/u-boot.lds
+++ b/cpu/mpc83xx/u-boot.lds
@@ -55,10 +55,8 @@ SECTIONS
*(.fixup)
*(.got1)
. = ALIGN(16);
- *(.rodata)
- *(.rodata1)
- *(.rodata.str1.4)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
diff --git a/cpu/ppc4xx/cpu_init.c b/cpu/ppc4xx/cpu_init.c
index b5d81f2..577d33f 100644
--- a/cpu/ppc4xx/cpu_init.c
+++ b/cpu/ppc4xx/cpu_init.c
@@ -321,33 +321,9 @@ cpu_init_f (void)
*/
int cpu_init_r (void)
{
-#if defined(CONFIG_405GP) || defined(CONFIG_405EP)
- bd_t *bd = gd->bd;
- unsigned long reg;
#if defined(CONFIG_405GP)
uint pvr = get_pvr();
-#endif
-
- /*
- * Write Ethernetaddress into on-chip register
- */
- reg = 0x00000000;
- reg |= bd->bi_enetaddr[0]; /* set high address */
- reg = reg << 8;
- reg |= bd->bi_enetaddr[1];
- out32 (EMAC_IAH, reg);
-
- reg = 0x00000000;
- reg |= bd->bi_enetaddr[2]; /* set low address */
- reg = reg << 8;
- reg |= bd->bi_enetaddr[3];
- reg = reg << 8;
- reg |= bd->bi_enetaddr[4];
- reg = reg << 8;
- reg |= bd->bi_enetaddr[5];
- out32 (EMAC_IAL, reg);
-#if defined(CONFIG_405GP)
/*
* Set edge conditioning circuitry on PPC405GPr
* for compatibility to existing PPC405GP designs.
@@ -356,7 +332,6 @@ int cpu_init_r (void)
mtdcr(ecr, 0x60606000);
}
#endif /* defined(CONFIG_405GP) */
-#endif /* defined(CONFIG_405GP) || defined(CONFIG_405EP) */
- return (0);
+ return 0;
}
diff --git a/disk/part.c b/disk/part.c
index e353cee..fdc49d3 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -184,7 +184,7 @@ void dev_print (block_dev_desc_t *dev_desc)
printf (" Supports 48-bit addressing\n");
#endif
#if defined(CONFIG_SYS_64BIT_LBA) && defined(CONFIG_SYS_64BIT_VSPRINTF)
- printf (" Capacity: %ld.%ld MB = %ld.%ld GB (%qd x %ld)\n",
+ printf (" Capacity: %ld.%ld MB = %ld.%ld GB (%Ld x %ld)\n",
mb_quot, mb_rem,
gb_quot, gb_rem,
lba,
diff --git a/doc/README.enetaddr b/doc/README.enetaddr
new file mode 100644
index 0000000..1d75aa3
--- /dev/null
+++ b/doc/README.enetaddr
@@ -0,0 +1,99 @@
+---------------------------------
+ Ethernet Address (MAC) Handling
+---------------------------------
+
+There are a variety of places in U-Boot where the MAC address is used, parsed,
+and stored. This document covers proper usage of each location and the moving
+of data between them.
+
+-----------
+ Locations
+-----------
+
+Here are the places where MAC addresses might be stored:
+
+ - board-specific location (eeprom, dedicated flash, ...)
+ Note: only used when mandatory due to hardware design etc...
+
+ - environment ("ethaddr", "eth1addr", ...) (see CONFIG_ETHADDR)
+ Note: this is the preferred way to permanently store MAC addresses
+
+ - ethernet data (struct eth_device -> enetaddr)
+ Note: these are temporary copies of the MAC address which exist only
+ after the respective init steps have run and only to make usage
+ in other places easier (to avoid constant env lookup/parsing)
+
+ - struct bd_info and/or device tree
+ Note: these are temporary copies of the MAC address only for the
+ purpose of passing this information to an OS kernel we are about
+ to boot
+
+-------
+ Usage
+-------
+
+If the hardware design mandates that the MAC address is stored in some special
+place (like EEPROM etc...), then the board specific init code (such as the
+board-specific misc_init_r() function) is responsible for locating the MAC
+address(es) and initializing the respective environment variable(s) from it.
+Note that this shall be done if, and only if, the environment does not already
+contain these environment variables, i.e. existing variable definitions must
+not be overwritten.
+
+During runtime, the ethernet layer will use the environment variables to sync
+the MAC addresses to the ethernet structures. All ethernet driver code should
+then only use the enetaddr member of the eth_device structure. This is done
+on every network command, so the ethernet copies will stay in sync.
+
+Any other code that wishes to access the MAC address should query the
+environment directly. The helper functions documented below should make
+working with this storage much smoother.
+
+---------
+ Helpers
+---------
+
+To assist in the management of these layers, a few helper functions exist. You
+should use these rather than attempt to do any kind of parsing/manipulation
+yourself as many common errors have arisen in the past.
+
+ * void eth_parse_enetaddr(const char *addr, uchar *enetaddr);
+
+Convert a string representation of a MAC address to the binary version.
+char *addr = "00:11:22:33:44:55";
+uchar enetaddr[6];
+eth_parse_enetaddr(addr, enetaddr);
+/* enetaddr now equals { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 } */
+
+ * int eth_getenv_enetaddr(char *name, uchar *enetaddr);
+
+Look up an environment variable and convert the stored address. If the address
+is valid, then the function returns 1. Otherwise, the function returns 0. In
+all cases, the enetaddr memory is initialized. If the env var is not found,
+then it is set to all zeros. The common function is_valid_ether_addr() is used
+to determine address validity.
+uchar enetaddr[6];
+if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
+ /* "ethaddr" is not set in the environment */
+ ... try and setup "ethaddr" in the env ...
+}
+/* enetaddr is now set to the value stored in the ethaddr env var */
+
+ * int eth_setenv_enetaddr(char *name, const uchar *enetaddr);
+
+Store the MAC address into the named environment variable. The return value is
+the same as the setenv() function.
+uchar enetaddr[6] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };
+eth_setenv_enetaddr("ethaddr", enetaddr);
+/* the "ethaddr" env var should now be set to "00:11:22:33:44:55" */
+
+ * the %pM format modifier
+
+The %pM format modifier can be used with any standard printf function to format
+the binary 6 byte array representation of a MAC address.
+uchar enetaddr[6] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };
+printf("The MAC is %pM\n", enetaddr);
+
+char buf[20];
+sprintf(buf, "%pM", enetaddr);
+/* the buf variable is now set to "00:11:22:33:44:55" */
diff --git a/drivers/misc/ali512x.c b/drivers/misc/ali512x.c
index d6a2c1f..cda3b0d 100644
--- a/drivers/misc/ali512x.c
+++ b/drivers/misc/ali512x.c
@@ -34,7 +34,7 @@
#include <common.h>
#include <asm/io.h>
-#include <asm/ic/ali512x.h>
+#include <ali512x.h>
/* ALI M5123 Logical device numbers:
diff --git a/drivers/net/3c589.c b/drivers/net/3c589.c
index 0cf8dff..f2c7d32 100644
--- a/drivers/net/3c589.c
+++ b/drivers/net/3c589.c
@@ -259,10 +259,13 @@ static void el_reset(bd_t *bd)
/* set mac addr */
{
- unsigned char *mac_addr = bd->bi_enetaddr;
+ uchar mac_addr[6];
int i;
- el_get_mac_addr( mac_addr );
+ if (!eth_getenv_enetaddr("ethaddr", mac_addr)) {
+ el_get_mac_addr(mac_addr);
+ eth_setenv_enetaddr("ethaddr", mac_addr);
+ }
GO_WINDOW(2);
VX_BUSY_WAIT;
diff --git a/drivers/net/4xx_enet.c b/drivers/net/4xx_enet.c
index 1978269..918373b 100644
--- a/drivers/net/4xx_enet.c
+++ b/drivers/net/4xx_enet.c
@@ -1927,24 +1927,22 @@ int ppc_4xx_eth_initialize (bd_t * bis)
memcpy(ethaddr[eth_num], "\0\0\0\0\0\0", 6);
for (eth_num = 0; eth_num < LAST_EMAC_NUM; eth_num++) {
+ int ethaddr_idx = eth_num + CONFIG_EMAC_NR_START;
switch (eth_num) {
default: /* fall through */
case 0:
- memcpy(ethaddr[eth_num + CONFIG_EMAC_NR_START],
- bis->bi_enetaddr, 6);
+ eth_getenv_enetaddr("ethaddr", ethaddr[ethaddr_idx]);
hw_addr[eth_num] = 0x0;
break;
#ifdef CONFIG_HAS_ETH1
case 1:
- memcpy(ethaddr[eth_num + CONFIG_EMAC_NR_START],
- bis->bi_enet1addr, 6);
+ eth_getenv_enetaddr("eth1addr", ethaddr[ethaddr_idx]);
hw_addr[eth_num] = 0x100;
break;
#endif
#ifdef CONFIG_HAS_ETH2
case 2:
- memcpy(ethaddr[eth_num + CONFIG_EMAC_NR_START],
- bis->bi_enet2addr, 6);
+ eth_getenv_enetaddr("eth2addr", ethaddr[ethaddr_idx]);
#if defined(CONFIG_460GT)
hw_addr[eth_num] = 0x300;
#else
@@ -1954,8 +1952,7 @@ int ppc_4xx_eth_initialize (bd_t * bis)
#endif
#ifdef CONFIG_HAS_ETH3
case 3:
- memcpy(ethaddr[eth_num + CONFIG_EMAC_NR_START],
- bis->bi_enet3addr, 6);
+ eth_getenv_enetaddr("eth3addr", ethaddr[ethaddr_idx]);
#if defined(CONFIG_460GT)
hw_addr[eth_num] = 0x400;
#else
diff --git a/drivers/net/bcm570x.c b/drivers/net/bcm570x.c
index 185764e..c250d44 100644
--- a/drivers/net/bcm570x.c
+++ b/drivers/net/bcm570x.c
@@ -450,8 +450,8 @@ int eth_init (bd_t * bis)
+ 1);
strcpy (pUmDevice->name, board_info[bcm570xDevices[i].board_id].name);
- memcpy (pDevice->NodeAddress, bis->bi_enetaddr, 6);
- LM_SetMacAddress (pDevice, bis->bi_enetaddr);
+ eth_getenv_enetaddr("ethaddr", pDevice->NodeAddress);
+ LM_SetMacAddress (pDevice);
/* Init queues .. */
QQ_InitQueue (&pUmDevice->rx_out_of_buf_q.Container,
MAX_RX_PACKET_DESC_COUNT);
diff --git a/drivers/net/bcm570x_lm.h b/drivers/net/bcm570x_lm.h
index 2ea6ca8..c07b767 100644
--- a/drivers/net/bcm570x_lm.h
+++ b/drivers/net/bcm570x_lm.h
@@ -371,7 +371,7 @@ LM_STATUS LM_Abort (PLM_DEVICE_BLOCK pDevice);
LM_STATUS LM_MulticastAdd (PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pMcAddress);
LM_STATUS LM_MulticastDel (PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pMcAddress);
LM_STATUS LM_MulticastClear (PLM_DEVICE_BLOCK pDevice);
-LM_STATUS LM_SetMacAddress (PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pMacAddress);
+LM_STATUS LM_SetMacAddress (PLM_DEVICE_BLOCK pDevice);
LM_STATUS LM_LoopbackAddress (PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pAddress);
LM_UINT32 LM_GetCrcCounter (PLM_DEVICE_BLOCK pDevice);
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index 23f934a..12d98c2 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -315,7 +315,7 @@ static int bfin_EMAC_init(struct eth_device *dev, bd_t *bd)
return -1;
/* Initialize EMAC address */
- bfin_EMAC_setup_addr(bd);
+ bfin_EMAC_setup_addr(dev->enetaddr);
/* Initialize TX and RX buffer */
for (i = 0; i < PKTBUFSRX; i++) {
@@ -373,16 +373,16 @@ static void bfin_EMAC_halt(struct eth_device *dev)
}
-void bfin_EMAC_setup_addr(bd_t *bd)
+void bfin_EMAC_setup_addr(uchar *enetaddr)
{
*pEMAC_ADDRLO =
- bd->bi_enetaddr[0] |
- bd->bi_enetaddr[1] << 8 |
- bd->bi_enetaddr[2] << 16 |
- bd->bi_enetaddr[3] << 24;
+ enetaddr[0] |
+ enetaddr[1] << 8 |
+ enetaddr[2] << 16 |
+ enetaddr[3] << 24;
*pEMAC_ADDRHI =
- bd->bi_enetaddr[4] |
- bd->bi_enetaddr[5] << 8;
+ enetaddr[4] |
+ enetaddr[5] << 8;
}
ADI_ETHER_BUFFER *SetupRxBuffer(int no)
diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h
index 084f533..8f467a3 100644
--- a/drivers/net/bfin_mac.h
+++ b/drivers/net/bfin_mac.h
@@ -61,6 +61,6 @@ static void bfin_EMAC_halt(struct eth_device *dev);
static int bfin_EMAC_send(struct eth_device *dev, volatile void *packet, int length);
static int bfin_EMAC_recv(struct eth_device *dev);
-static void bfin_EMAC_setup_addr(bd_t *bd);
+void bfin_EMAC_setup_addr(uchar *enetaddr);
#endif
diff --git a/drivers/net/cs8900.c b/drivers/net/cs8900.c
index 35a9baf..0557fcd 100644
--- a/drivers/net/cs8900.c
+++ b/drivers/net/cs8900.c
@@ -110,18 +110,14 @@ static void eth_reginit (void)
put_reg (PP_LineCTL, PP_LineCTL_Rx | PP_LineCTL_Tx);
}
-void cs8900_get_enetaddr (uchar * addr)
+void cs8900_get_enetaddr (void)
{
int i;
- unsigned char env_enetaddr[6];
- char *tmp = getenv ("ethaddr");
- char *end;
-
- for (i=0; i<6; i++) {
- env_enetaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
- if (tmp)
- tmp = (*end) ? end+1 : end;
- }
+ uchar enetaddr[6];
+
+ /* if the env is setup, then bail */
+ if (eth_getenv_enetaddr("ethaddr", enetaddr))
+ return;
/* verify chip id */
if (get_reg_init_bus (PP_ChipID) != 0x630e)
@@ -135,35 +131,12 @@ void cs8900_get_enetaddr (uchar * addr)
unsigned int Addr;
Addr = get_reg (PP_IA + i * 2);
- addr[i * 2] = Addr & 0xFF;
- addr[i * 2 + 1] = Addr >> 8;
+ enetaddr[i * 2] = Addr & 0xFF;
+ enetaddr[i * 2 + 1] = Addr >> 8;
}
- if (memcmp(env_enetaddr, "\0\0\0\0\0\0", 6) != 0 &&
- memcmp(env_enetaddr, addr, 6) != 0) {
- printf ("\nWarning: MAC addresses don't match:\n");
- printf ("\tHW MAC address: "
- "%02X:%02X:%02X:%02X:%02X:%02X\n",
- addr[0], addr[1],
- addr[2], addr[3],
- addr[4], addr[5] );
- printf ("\t\"ethaddr\" value: "
- "%02X:%02X:%02X:%02X:%02X:%02X\n",
- env_enetaddr[0], env_enetaddr[1],
- env_enetaddr[2], env_enetaddr[3],
- env_enetaddr[4], env_enetaddr[5]) ;
- debug ("### Set MAC addr from environment\n");
- memcpy (addr, env_enetaddr, 6);
- }
- if (!tmp) {
- char ethaddr[20];
- sprintf (ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X",
- addr[0], addr[1],
- addr[2], addr[3],
- addr[4], addr[5]) ;
- debug ("### Set environment from HW MAC addr = \"%s\"\n", ethaddr);
- setenv ("ethaddr", ethaddr);
- }
+ eth_setenv_enetaddr("ethaddr", enetaddr);
+ debug("### Set environment from HW MAC addr = \"%pM\"\n", enetaddr);
}
}
@@ -178,6 +151,8 @@ void eth_halt (void)
int eth_init (bd_t * bd)
{
+ uchar *enetaddr[6];
+
/* verify chip id */
if (get_reg_init_bus (PP_ChipID) != 0x630e) {
printf ("CS8900 Ethernet chip not found?!\n");
@@ -186,9 +161,10 @@ int eth_init (bd_t * bd)
eth_reset ();
/* set the ethernet address */
- put_reg (PP_IA + 0, bd->bi_enetaddr[0] | (bd->bi_enetaddr[1] << 8));
- put_reg (PP_IA + 2, bd->bi_enetaddr[2] | (bd->bi_enetaddr[3] << 8));
- put_reg (PP_IA + 4, bd->bi_enetaddr[4] | (bd->bi_enetaddr[5] << 8));
+ eth_getenv_enetaddr("ethaddr", enetaddr);
+ put_reg (PP_IA + 0, enetaddr[0] | (enetaddr[1] << 8));
+ put_reg (PP_IA + 2, enetaddr[2] | (enetaddr[3] << 8));
+ put_reg (PP_IA + 4, enetaddr[4] | (enetaddr[5] << 8));
eth_reginit ();
return 0;
diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c
index c0137a7..5ae53e8 100644
--- a/drivers/net/dc2114x.c
+++ b/drivers/net/dc2114x.c
@@ -752,11 +752,14 @@ static void update_srom(struct eth_device *dev, bd_t *bis)
0x0000, 0x0000, 0x0000, 0x0000, /* 38 */
0x0000, 0x0000, 0x0000, 0x4e07, /* 3c */
};
+ uchar enetaddr[6];
/* Ethernet Addr... */
- eeprom[0x0a] = ((bis->bi_enetaddr[1] & 0xff) << 8) | (bis->bi_enetaddr[0] & 0xff);
- eeprom[0x0b] = ((bis->bi_enetaddr[3] & 0xff) << 8) | (bis->bi_enetaddr[2] & 0xff);
- eeprom[0x0c] = ((bis->bi_enetaddr[5] & 0xff) << 8) | (bis->bi_enetaddr[4] & 0xff);
+ if (!eth_getenv_enetaddr("ethaddr", enetaddr))
+ return;
+ eeprom[0x0a] = (enetaddr[1] << 8) | enetaddr[0];
+ eeprom[0x0b] = (enetaddr[3] << 8) | enetaddr[2];
+ eeprom[0x0c] = (enetaddr[5] << 8) | enetaddr[4];
for (i=0; i<0x40; i++) {
write_srom(dev, DE4X5_APROM, i, eeprom[i]);
diff --git a/drivers/net/dm9000x.c b/drivers/net/dm9000x.c
index ffb739d..c52d307 100644
--- a/drivers/net/dm9000x.c
+++ b/drivers/net/dm9000x.c
@@ -287,6 +287,7 @@ eth_init(bd_t * bd)
int i, oft, lnk;
u8 io_mode;
struct board_info *db = &dm9000_info;
+ uchar enetaddr[6];
DM9000_DBG("eth_init()\n");
@@ -345,32 +346,19 @@ eth_init(bd_t * bd)
DM9000_iow(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS);
/* Set Node address */
+ if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
#if !defined(CONFIG_AT91SAM9261EK)
- for (i = 0; i < 6; i++)
- ((u16 *) bd->bi_enetaddr)[i] = read_srom_word(i);
+ for (i = 0; i < 6; i++)
+ enetaddr[i] = read_srom_word(i);
+ eth_setenv_enetaddr("ethaddr", enetaddr);
#endif
-
- if (is_zero_ether_addr(bd->bi_enetaddr) ||
- is_multicast_ether_addr(bd->bi_enetaddr)) {
- /* try reading from environment */
- u8 i;
- char *s, *e;
- s = getenv ("ethaddr");
- for (i = 0; i < 6; ++i) {
- bd->bi_enetaddr[i] = s ?
- simple_strtoul (s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
}
- printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", bd->bi_enetaddr[0],
- bd->bi_enetaddr[1], bd->bi_enetaddr[2], bd->bi_enetaddr[3],
- bd->bi_enetaddr[4], bd->bi_enetaddr[5]);
+ printf("MAC: %pM\n", enetaddr);
/* fill device MAC address registers */
for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++)
- DM9000_iow(oft, bd->bi_enetaddr[i]);
+ DM9000_iow(oft, enetaddr[i]);
for (i = 0, oft = 0x16; i < 8; i++, oft++)
DM9000_iow(oft, 0xff);
diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c
index 5c24b0d..3238a50 100644
--- a/drivers/net/enc28j60.c
+++ b/drivers/net/enc28j60.c
@@ -330,6 +330,7 @@ static int rxResetCounter = 0;
int eth_init (bd_t * bis)
{
unsigned char estatVal;
+ uchar enetaddr[6];
/* configure GPIO */
(*((volatile unsigned long *) IO1DIR)) |= ENC_SPI_SLAVE_CS;
@@ -351,7 +352,8 @@ int eth_init (bd_t * bis)
/* initialize controller */
encReset ();
- encInit (bis->bi_enetaddr);
+ eth_getenv_enetaddr("ethaddr", enetaddr);
+ encInit (enetaddr);
m_nic_bfs (CTL_REG_ECON1, ENC_ECON1_RXEN); /* enable receive */
diff --git a/drivers/net/fsl_mcdmafec.c b/drivers/net/fsl_mcdmafec.c
index d056010..35a6dfb 100644
--- a/drivers/net/fsl_mcdmafec.c
+++ b/drivers/net/fsl_mcdmafec.c
@@ -369,6 +369,7 @@ static int fec_init(struct eth_device *dev, bd_t * bd)
struct fec_info_dma *info = dev->priv;
volatile fecdma_t *fecp = (fecdma_t *) (info->iobase);
int i;
+ uchar enetaddr[6];
#ifdef ET_DEBUG
printf("fec_init: iobase 0x%08x ...\n", info->iobase);
@@ -397,11 +398,11 @@ static int fec_init(struct eth_device *dev, bd_t * bd)
fecp->eir = 0xffffffff;
/* Set station address */
- if ((u32) fecp == CONFIG_SYS_FEC0_IOBASE) {
- fec_set_hwaddr(fecp, bd->bi_enetaddr);
- } else {
- fec_set_hwaddr(fecp, bd->bi_enet1addr);
- }
+ if ((u32) fecp == CONFIG_SYS_FEC0_IOBASE)
+ eth_getenv_enetaddr("ethaddr", enetaddr);
+ else
+ eth_getenv_enetaddr("eth1addr", enetaddr);
+ fec_set_hwaddr(fecp, enetaddr);
/* Set Opcode/Pause Duration Register */
fecp->opd = 0x00010020;
diff --git a/drivers/net/ks8695eth.c b/drivers/net/ks8695eth.c
index 7f3e0c2..5ea6e7f 100644
--- a/drivers/net/ks8695eth.c
+++ b/drivers/net/ks8695eth.c
@@ -150,13 +150,7 @@ void eth_reset(bd_t *bd)
ks8695_write(KS8695_LAN_DMA_RX, 0x71);
ks8695_write(KS8695_LAN_DMA_RX_START, 0x1);
- printf("KS8695 ETHERNET: ");
- for (i = 0; (i < 5); i++) {
- bd->bi_enetaddr[i] = eth_mac[i];
- printf("%02x:", eth_mac[i]);
- }
- bd->bi_enetaddr[i] = eth_mac[i];
- printf("%02x\n", eth_mac[i]);
+ printf("KS8695 ETHERNET: %pM\n", eth_mac);
}
/****************************************************************************/
diff --git a/drivers/net/lan91c96.c b/drivers/net/lan91c96.c
index 318bdf4..65565bc 100644
--- a/drivers/net/lan91c96.c
+++ b/drivers/net/lan91c96.c
@@ -606,10 +606,8 @@ static int smc_open (bd_t *bd)
SMC_SELECT_BANK (1);
err = smc_get_ethaddr (bd); /* set smc_mac_addr, and sync it with u-boot globals */
- if (err < 0) {
- memset (bd->bi_enetaddr, 0, 6); /* hack to make error stick! upper code will abort if not set */
- return (-1); /* upper code ignores this, but NOT bi_enetaddr */
- }
+ if (err < 0)
+ return -1;
#ifdef USE_32_BIT
for (i = 0; i < 6; i += 2) {
word address;
@@ -869,69 +867,20 @@ static int smc_hw_init ()
int smc_get_ethaddr (bd_t * bd)
{
- int env_size = 0;
- int rom_valid = 0;
- int env_present = 0;
- int reg = 0;
- char *s = NULL;
- char *e = NULL;
- char *v_mac, es[] = "11:22:33:44:55:66";
- char s_env_mac[64];
- uchar v_env_mac[6];
- uchar v_rom_mac[6];
-
- env_size = getenv_r ("ethaddr", s_env_mac, sizeof (s_env_mac));
- if (env_size != sizeof(es)) { /* Ignore if env is bad or not set */
- printf ("\n*** Warning: ethaddr is not set properly, ignoring!!\n");
- } else {
- env_present = 1;
- s = s_env_mac;
-
- for (reg = 0; reg < 6; ++reg) { /* turn string into mac value */
- v_env_mac[reg] = s ? simple_strtoul (s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
- }
+ uchar v_mac[6];
- rom_valid = get_rom_mac (v_rom_mac); /* get ROM mac value if any */
-
- if (!env_present) { /* if NO env */
- if (rom_valid) { /* but ROM is valid */
- v_mac = (char *)v_rom_mac;
- sprintf (s_env_mac, "%02X:%02X:%02X:%02X:%02X:%02X",
- v_mac[0], v_mac[1], v_mac[2], v_mac[3],
- v_mac[4], v_mac[5]);
- setenv ("ethaddr", s_env_mac);
- } else { /* no env, bad ROM */
- printf ("\n*** ERROR: ethaddr is NOT set !!\n");
- return (-1);
+ if (!eth_getenv_enetaddr("ethaddr", v_mac)) {
+ /* get ROM mac value if any */
+ if (!get_rom_mac(v_mac)) {
+ printf("\n*** ERROR: ethaddr is NOT set !!\n");
+ return -1;
}
- } else { /* good env, don't care ROM */
- v_mac = (char *)v_env_mac; /* always use a good env over a ROM */
+ eth_setenv_enetaddr("ethaddr", v_mac);
}
- if (env_present && rom_valid) { /* if both env and ROM are good */
- if (memcmp (v_env_mac, v_rom_mac, 6) != 0) {
- printf ("\nWarning: MAC addresses don't match:\n");
- printf ("\tHW MAC address: "
- "%02X:%02X:%02X:%02X:%02X:%02X\n",
- v_rom_mac[0], v_rom_mac[1],
- v_rom_mac[2], v_rom_mac[3],
- v_rom_mac[4], v_rom_mac[5] );
- printf ("\t\"ethaddr\" value: "
- "%02X:%02X:%02X:%02X:%02X:%02X\n",
- v_env_mac[0], v_env_mac[1],
- v_env_mac[2], v_env_mac[3],
- v_env_mac[4], v_env_mac[5]) ;
- debug ("### Set MAC addr from environment\n");
- }
- }
- memcpy (bd->bi_enetaddr, v_mac, 6); /* update global address to match env (allows env changing) */
- smc_set_mac_addr ((unsigned char *)v_mac); /* use old function to update smc default */
- PRINTK("Using MAC Address %02X:%02X:%02X:%02X:%02X:%02X\n", v_mac[0], v_mac[1],
- v_mac[2], v_mac[3], v_mac[4], v_mac[5]);
- return (0);
+ smc_set_mac_addr(v_mac); /* use old function to update smc default */
+ PRINTK("Using MAC Address %pM\n", v_mac);
+ return 0;
}
/*
diff --git a/drivers/net/mcffec.c b/drivers/net/mcffec.c
index 18240a8..64be5de 100644
--- a/drivers/net/mcffec.c
+++ b/drivers/net/mcffec.c
@@ -416,7 +416,7 @@ int fec_init(struct eth_device *dev, bd_t * bd)
struct fec_info_s *info = dev->priv;
volatile fec_t *fecp = (fec_t *) (info->iobase);
int i;
- u8 *ea = NULL;
+ uchar ea[6];
fecpin_setclear(dev, 1);
@@ -444,25 +444,25 @@ int fec_init(struct eth_device *dev, bd_t * bd)
if ((u32) fecp == CONFIG_SYS_FEC0_IOBASE) {
#ifdef CONFIG_SYS_FEC1_IOBASE
volatile fec_t *fecp1 = (fec_t *) (CONFIG_SYS_FEC1_IOBASE);
- ea = &bd->bi_enet1addr[0];
+ eth_getenv_enetaddr("eth1addr", ea);
fecp1->palr =
(ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
fecp1->paur = (ea[4] << 24) | (ea[5] << 16);
#endif
- ea = &bd->bi_enetaddr[0];
+ eth_getenv_enetaddr("ethaddr", ea);
fecp->palr =
(ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
fecp->paur = (ea[4] << 24) | (ea[5] << 16);
} else {
#ifdef CONFIG_SYS_FEC0_IOBASE
volatile fec_t *fecp0 = (fec_t *) (CONFIG_SYS_FEC0_IOBASE);
- ea = &bd->bi_enetaddr[0];
+ eth_getenv_enetaddr("ethaddr", ea);
fecp0->palr =
(ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
fecp0->paur = (ea[4] << 24) | (ea[5] << 16);
#endif
#ifdef CONFIG_SYS_FEC1_IOBASE
- ea = &bd->bi_enet1addr[0];
+ eth_getenv_enetaddr("eth1addr", ea);
fecp->palr =
(ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
fecp->paur = (ea[4] << 24) | (ea[5] << 16);
diff --git a/drivers/net/rtl8019.c b/drivers/net/rtl8019.c
index 3ddf917..f516afe 100644
--- a/drivers/net/rtl8019.c
+++ b/drivers/net/rtl8019.c
@@ -91,6 +91,7 @@ void eth_halt (void)
int eth_init (bd_t * bd)
{
+ uchar enetaddr[6];
eth_reset ();
put_reg (RTL8019_COMMAND, RTL8019_PAGE0STOP);
put_reg (RTL8019_DATACONFIGURATION, 0x48);
@@ -105,12 +106,13 @@ int eth_init (bd_t * bd)
put_reg (RTL8019_INTERRUPTSTATUS, 0xff);
put_reg (RTL8019_INTERRUPTMASK, 0x11); /*b; */
put_reg (RTL8019_COMMAND, RTL8019_PAGE1STOP);
- put_reg (RTL8019_PHYSICALADDRESS0, bd->bi_enetaddr[0]);
- put_reg (RTL8019_PHYSICALADDRESS1, bd->bi_enetaddr[1]);
- put_reg (RTL8019_PHYSICALADDRESS2, bd->bi_enetaddr[2]);
- put_reg (RTL8019_PHYSICALADDRESS3, bd->bi_enetaddr[3]);
- put_reg (RTL8019_PHYSICALADDRESS4, bd->bi_enetaddr[4]);
- put_reg (RTL8019_PHYSICALADDRESS5, bd->bi_enetaddr[5]);
+ eth_getenv_enetaddr("ethaddr", enetaddr);
+ put_reg (RTL8019_PHYSICALADDRESS0, enetaddr[0]);
+ put_reg (RTL8019_PHYSICALADDRESS1, enetaddr[1]);
+ put_reg (RTL8019_PHYSICALADDRESS2, enetaddr[2]);
+ put_reg (RTL8019_PHYSICALADDRESS3, enetaddr[3]);
+ put_reg (RTL8019_PHYSICALADDRESS4, enetaddr[4]);
+ put_reg (RTL8019_PHYSICALADDRESS5, enetaddr[5]);
put_reg (RTL8019_MULTIADDRESS0, 0x00);
put_reg (RTL8019_MULTIADDRESS1, 0x00);
put_reg (RTL8019_MULTIADDRESS2, 0x00);
diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c
index e9f6391..f8c14b4 100644
--- a/drivers/net/rtl8169.c
+++ b/drivers/net/rtl8169.c
@@ -750,7 +750,7 @@ static int rtl_init(struct eth_device *dev, bd_t *bis)
/* Get MAC address. FIXME: read EEPROM */
for (i = 0; i < MAC_ADDR_LEN; i++)
- bis->bi_enetaddr[i] = dev->enetaddr[i] = RTL_R8(MAC0 + i);
+ dev->enetaddr[i] = RTL_R8(MAC0 + i);
#ifdef DEBUG_RTL8169
printf("chipset = %d\n", tpc->chipset);
diff --git a/drivers/net/s3c4510b_eth.c b/drivers/net/s3c4510b_eth.c
index 6dcb244..818ed3d 100644
--- a/drivers/net/s3c4510b_eth.c
+++ b/drivers/net/s3c4510b_eth.c
@@ -100,7 +100,7 @@ int eth_init(bd_t *bis)
ETH *eth = &m_eth;
/* store our MAC address */
- eth->m_mac = bis->bi_enetaddr;
+ eth_getenv_enetaddr("ethaddr", eth->m_mac);
/* setup DBMA and MAC */
PUT_REG( REG_BDMARXCON, ETH_BRxRS); /* reset BDMA RX machine */
diff --git a/drivers/net/s3c4510b_eth.h b/drivers/net/s3c4510b_eth.h
index 048307f..18a52a7 100644
--- a/drivers/net/s3c4510b_eth.h
+++ b/drivers/net/s3c4510b_eth.h
@@ -296,7 +296,7 @@ typedef struct __ETH {
TX_FrameDescriptor *m_baseTX_FD; /* pointer to base TX frame descriptor */
RX_FrameDescriptor *m_curRX_FD; /* pointer to current RX frame descriptor */
RX_FrameDescriptor *m_baseRX_FD; /* pointer to base RX frame descriptor */
- u8 *m_mac; /* pointer to our MAC address */
+ u8 m_mac[6]; /* pointer to our MAC address */
} ETH;
#endif
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index bee3f02..f24ded2 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -514,6 +514,7 @@ static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd)
int port = eth->port, ret = 0;
u32 val, phy_status;
struct sh_eth_info *port_info = &eth->port_info[port];
+ struct eth_device *dev = port_info->dev;
/* Configure e-dmac registers */
outl((inl(EDMR(port)) & ~EMDR_DESC_R) | EDMR_EL, EDMR(port));
@@ -529,11 +530,11 @@ static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd)
outl(0, ECSIPR(port));
/* Set Mac address */
- val = bd->bi_enetaddr[0] << 24 | bd->bi_enetaddr[1] << 16 |
- bd->bi_enetaddr[2] << 8 | bd->bi_enetaddr[3];
+ val = dev->enetaddr[0] << 24 | dev->enetaddr[1] << 16 |
+ dev->enetaddr[2] << 8 | dev->enetaddr[3];
outl(val, MAHR(port));
- val = bd->bi_enetaddr[4] << 8 | bd->bi_enetaddr[5];
+ val = dev->enetaddr[4] << 8 | dev->enetaddr[5];
outl(val, MALR(port));
outl(RFLR_RFL_MIN, RFLR(port));
@@ -589,24 +590,6 @@ static void sh_eth_stop(struct sh_eth_dev *eth)
outl(~EDRRR_R, EDRRR(eth->port));
}
-static int sh_eth_get_mac(bd_t *bd)
-{
- char *s, *e;
-
- s = getenv("ethaddr");
- if (s != NULL) {
- int i;
- for (i = 0; i < 6; ++i) {
- bd->bi_enetaddr[i] = s ? simple_strtoul(s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
- } else {
- puts("Please set MAC address\n");
- }
- return 0;
-}
-
int sh_eth_init(struct eth_device *dev, bd_t *bd)
{
int ret = 0;
@@ -680,7 +663,8 @@ int sh_eth_initialize(bd_t *bd)
/* Register Device to EtherNet subsystem */
eth_register(dev);
- sh_eth_get_mac(bd);
+ if (!eth_getenv_enetaddr("ethaddr", dev->enetaddr))
+ puts("Please set MAC address\n");
return ret;
diff --git a/drivers/net/smc91111.c b/drivers/net/smc91111.c
index 82abb02..b41e4d2 100644
--- a/drivers/net/smc91111.c
+++ b/drivers/net/smc91111.c
@@ -834,10 +834,8 @@ static int smc_open (bd_t * bd)
SMC_SELECT_BANK (1);
err = smc_get_ethaddr (bd); /* set smc_mac_addr, and sync it with u-boot globals */
- if (err < 0) {
- memset (bd->bi_enetaddr, 0, 6); /* hack to make error stick! upper code will abort if not set */
- return (-1); /* upper code ignores this, but NOT bi_enetaddr */
- }
+ if (err < 0)
+ return -1;
#ifdef USE_32_BIT
for (i = 0; i < 6; i += 2) {
word address;
@@ -1535,66 +1533,20 @@ int eth_send(volatile void *packet, int length) {
int smc_get_ethaddr (bd_t * bd)
{
- int env_size, rom_valid, env_present = 0, reg;
- char *s = NULL, *e, es[] = "11:22:33:44:55:66";
- char s_env_mac[64];
- uchar v_env_mac[6], v_rom_mac[6], *v_mac;
-
- env_size = getenv_r ("ethaddr", s_env_mac, sizeof (s_env_mac));
- if ((env_size > 0) && (env_size < sizeof (es))) { /* exit if env is bad */
- printf ("\n*** ERROR: ethaddr is not set properly!!\n");
- return (-1);
- }
+ uchar v_mac[6];
- if (env_size > 0) {
- env_present = 1;
- s = s_env_mac;
- }
-
- for (reg = 0; reg < 6; ++reg) { /* turn string into mac value */
- v_env_mac[reg] = s ? simple_strtoul (s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
-
- rom_valid = get_rom_mac (v_rom_mac); /* get ROM mac value if any */
-
- if (!env_present) { /* if NO env */
- if (rom_valid) { /* but ROM is valid */
- v_mac = v_rom_mac;
- sprintf (s_env_mac, "%02X:%02X:%02X:%02X:%02X:%02X",
- v_mac[0], v_mac[1], v_mac[2], v_mac[3],
- v_mac[4], v_mac[5]);
- setenv ("ethaddr", s_env_mac);
- } else { /* no env, bad ROM */
- printf ("\n*** ERROR: ethaddr is NOT set !!\n");
- return (-1);
+ if (!eth_getenv_enetaddr("ethaddr", v_mac)) {
+ /* get ROM mac value if any */
+ if (!get_rom_mac(v_mac)) {
+ printf("\n*** ERROR: ethaddr is NOT set !!\n");
+ return -1;
}
- } else { /* good env, don't care ROM */
- v_mac = v_env_mac; /* always use a good env over a ROM */
+ eth_setenv_enetaddr("ethaddr", v_mac);
}
- if (env_present && rom_valid) { /* if both env and ROM are good */
- if (memcmp (v_env_mac, v_rom_mac, 6) != 0) {
- printf ("\nWarning: MAC addresses don't match:\n");
- printf ("\tHW MAC address: "
- "%02X:%02X:%02X:%02X:%02X:%02X\n",
- v_rom_mac[0], v_rom_mac[1],
- v_rom_mac[2], v_rom_mac[3],
- v_rom_mac[4], v_rom_mac[5] );
- printf ("\t\"ethaddr\" value: "
- "%02X:%02X:%02X:%02X:%02X:%02X\n",
- v_env_mac[0], v_env_mac[1],
- v_env_mac[2], v_env_mac[3],
- v_env_mac[4], v_env_mac[5]) ;
- debug ("### Set MAC addr from environment\n");
- }
- }
- memcpy (bd->bi_enetaddr, v_mac, 6); /* update global address to match env (allows env changing) */
- smc_set_mac_addr ((uchar *)v_mac); /* use old function to update smc default */
- PRINTK("Using MAC Address %02X:%02X:%02X:%02X:%02X:%02X\n", v_mac[0], v_mac[1],
- v_mac[2], v_mac[3], v_mac[4], v_mac[5]);
- return (0);
+ smc_set_mac_addr(v_mac); /* use old function to update smc default */
+ PRINTK("Using MAC Address %pM\n", v_mac);
+ return 0;
}
int get_rom_mac (uchar *v_rom_mac)
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 1ded8f0..30f2dc2 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -39,15 +39,10 @@ void pkt_data_push(u32 addr, u32 val) \
static int smx911x_handle_mac_address(bd_t *bd)
{
unsigned long addrh, addrl;
- unsigned char *m = bd->bi_enetaddr;
+ uchar m[6];
/* if the environment has a valid mac address then use it */
- if ((m[0] | m[1] | m[2] | m[3] | m[4] | m[5])) {
- addrl = m[0] | m[1] << 8 | m[2] << 16 | m[3] << 24;
- addrh = m[4] | m[5] << 8;
- smc911x_set_mac_csr(ADDRH, addrh);
- smc911x_set_mac_csr(ADDRL, addrl);
- } else {
+ if (!eth_getenv_enetaddr("ethaddr", m)) {
/* if not, try to get one from the eeprom */
addrh = smc911x_get_mac_csr(ADDRH);
addrl = smc911x_get_mac_csr(ADDRL);
@@ -65,10 +60,11 @@ static int smx911x_handle_mac_address(bd_t *bd)
"and no eeprom found\n");
return -1;
}
+
+ eth_setenv_enetaddr("ethaddr", m);
}
- printf(DRIVERNAME ": MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
- m[0], m[1], m[2], m[3], m[4], m[5]);
+ printf(DRIVERNAME ": MAC %pM\n", m);
return 0;
}
diff --git a/drivers/net/tigon3.c b/drivers/net/tigon3.c
index e4e004e..33cb447 100644
--- a/drivers/net/tigon3.c
+++ b/drivers/net/tigon3.c
@@ -2463,7 +2463,7 @@ LM_STATUS LM_ResetAdapter (PLM_DEVICE_BLOCK pDevice)
#endif /* T3_JUMBO_RCV_ENTRY_COUNT */
/* Configure the MAC address. */
- LM_SetMacAddress (pDevice, pDevice->NodeAddress);
+ LM_SetMacAddress (pDevice);
/* Initialize the transmit random backoff seed. */
Value32 = (pDevice->NodeAddress[0] + pDevice->NodeAddress[1] +
@@ -3428,7 +3428,7 @@ LM_STATUS LM_Halt (PLM_DEVICE_BLOCK pDevice)
(pDevice->SubsystemId << 16) | pDevice->SubsystemVendorId);
/* Reprogram the MAC address. */
- LM_SetMacAddress (pDevice, pDevice->NodeAddress);
+ LM_SetMacAddress (pDevice);
return LM_STATUS_SUCCESS;
} /* LM_Halt */
@@ -3833,9 +3833,10 @@ LM_STATUS LM_MulticastClear (PLM_DEVICE_BLOCK pDevice)
/* */
/* Return: */
/******************************************************************************/
-LM_STATUS LM_SetMacAddress (PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pMacAddress)
+LM_STATUS LM_SetMacAddress (PLM_DEVICE_BLOCK pDevice)
{
LM_UINT32 j;
+ PLM_UINT8 pMacAddress = pDevice->NodeAddress;
for (j = 0; j < 4; j++) {
REG_WR (pDevice, MacCtrl.MacAddr[j].High,
diff --git a/drivers/net/xilinx_emac.c b/drivers/net/xilinx_emac.c
index c7f1a2a..a489aa9 100644
--- a/drivers/net/xilinx_emac.c
+++ b/drivers/net/xilinx_emac.c
@@ -166,6 +166,7 @@ void eth_halt(void)
int eth_init(bd_t * bis)
{
+ uchar enetaddr[6];
u32 helpreg;
debug ("EMAC Initialization Started\n\r");
@@ -200,15 +201,16 @@ int eth_init(bd_t * bis)
helpreg &= ~(XEM_ECR_XMIT_ENABLE_MASK | XEM_ECR_RECV_ENABLE_MASK);
out_be32 (emac.baseaddress + XEM_ECR_OFFSET, helpreg);
- if (!getenv("ethaddr")) {
- memcpy(bis->bi_enetaddr, emacaddr, ENET_ADDR_LENGTH);
+ if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
+ memcpy(enetaddr, emacaddr, ENET_ADDR_LENGTH);
+ eth_setenv_enetaddr("ethaddr", enetaddr);
}
/* Set the device station address high and low registers */
- helpreg = (bis->bi_enetaddr[0] << 8) | bis->bi_enetaddr[1];
+ helpreg = (enetaddr[0] << 8) | enetaddr[1];
out_be32 (emac.baseaddress + XEM_SAH_OFFSET, helpreg);
- helpreg = (bis->bi_enetaddr[2] << 24) | (bis->bi_enetaddr[3] << 16) |
- (bis->bi_enetaddr[4] << 8) | bis->bi_enetaddr[5];
+ helpreg = (enetaddr[2] << 24) | (enetaddr[3] << 16) |
+ (enetaddr[4] << 8) | enetaddr[5];
out_be32 (emac.baseaddress + XEM_SAL_OFFSET, helpreg);
helpreg = XEM_ECR_UNICAST_ENABLE_MASK | XEM_ECR_BROAD_ENABLE_MASK |
diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c
index 0e96ef1..cf39573 100644
--- a/drivers/net/xilinx_emaclite.c
+++ b/drivers/net/xilinx_emaclite.c
@@ -140,12 +140,15 @@ void eth_halt (void)
int eth_init (bd_t * bis)
{
+ uchar enetaddr[6];
+
debug ("EmacLite Initialization Started\n");
memset (&emaclite, 0, sizeof (xemaclite));
emaclite.baseaddress = XILINX_EMACLITE_BASEADDR;
- if (!getenv("ethaddr")) {
- memcpy(bis->bi_enetaddr, emacaddr, ENET_ADDR_LENGTH);
+ if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
+ memcpy(enetaddr, emacaddr, ENET_ADDR_LENGTH);
+ eth_setenv_enetaddr("ethaddr", enetaddr);
}
/*
@@ -154,7 +157,7 @@ int eth_init (bd_t * bis)
/* Restart PING TX */
out_be32 (emaclite.baseaddress + XEL_TSR_OFFSET, 0);
/* Copy MAC address */
- xemaclite_alignedwrite (bis->bi_enetaddr,
+ xemaclite_alignedwrite (enetaddr,
emaclite.baseaddress, ENET_ADDR_LENGTH);
/* Set the length */
out_be32 (emaclite.baseaddress + XEL_TPLR_OFFSET, ENET_ADDR_LENGTH);
@@ -167,7 +170,7 @@ int eth_init (bd_t * bis)
#ifdef CONFIG_XILINX_EMACLITE_TX_PING_PONG
/* The same operation with PONG TX */
out_be32 (emaclite.baseaddress + XEL_TSR_OFFSET + XEL_BUFFER_OFFSET, 0);
- xemaclite_alignedwrite (bis->bi_enetaddr, emaclite.baseaddress +
+ xemaclite_alignedwrite (enetaddr, emaclite.baseaddress +
XEL_BUFFER_OFFSET, ENET_ADDR_LENGTH);
out_be32 (emaclite.baseaddress + XEL_TPLR_OFFSET, ENET_ADDR_LENGTH);
out_be32 (emaclite.baseaddress + XEL_TSR_OFFSET + XEL_BUFFER_OFFSET,
diff --git a/examples/mips.lds b/examples/mips.lds
index 939e0e6..717b201 100644
--- a/examples/mips.lds
+++ b/examples/mips.lds
@@ -34,7 +34,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/examples/nios.lds b/examples/nios.lds
index 18072f7..4c1080b 100644
--- a/examples/nios.lds
+++ b/examples/nios.lds
@@ -37,7 +37,7 @@ SECTIONS
. = ALIGN(4);
.rodata :
{
- *(.rodata)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
__rodata_end = .;
diff --git a/examples/nios2.lds b/examples/nios2.lds
index 6a100dc..a3e5ea8 100644
--- a/examples/nios2.lds
+++ b/examples/nios2.lds
@@ -33,8 +33,7 @@ SECTIONS
*(.text)
*(.text.*)
*(.gnu.linkonce.t*)
- *(.rodata)
- *(.rodata.*)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
*(.gnu.linkonce.r*)
}
. = ALIGN (4);
diff --git a/examples/sparc.lds b/examples/sparc.lds
index 7592544..9733daa 100644
--- a/examples/sparc.lds
+++ b/examples/sparc.lds
@@ -37,7 +37,7 @@ SECTIONS
. = ALIGN(4);
.rodata :
{
- *(.rodata)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
__rodata_end = .;
diff --git a/fs/Makefile b/fs/Makefile
index 8bbd563..22aad12 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -29,6 +29,7 @@ subdirs-$(CONFIG_CMD_FDOS) += fdos
subdirs-$(CONFIG_CMD_JFFS2) += jffs2
subdirs-$(CONFIG_CMD_REISER) += reiserfs
subdirs-$(CONFIG_YAFFS2) += yaffs2
+subdirs-$(CONFIG_CMD_UBIFS) += ubifs
SUBDIRS := $(subdirs-y)
diff --git a/fs/ubifs/Makefile b/fs/ubifs/Makefile
new file mode 100644
index 0000000..8328843
--- /dev/null
+++ b/fs/ubifs/Makefile
@@ -0,0 +1,52 @@
+#
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# (C) Copyright 2003
+# Pavel Bartusek, Sysgo Real-Time Solutions AG, pba@sysgo.de
+#
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)libubifs.a
+
+COBJS-$(CONFIG_CMD_UBIFS) := ubifs.o io.o super.o sb.o master.o lpt.o
+COBJS-$(CONFIG_CMD_UBIFS) += lpt_commit.o scan.o lprops.o
+COBJS-$(CONFIG_CMD_UBIFS) += tnc.o tnc_misc.o debug.o crc16.o budget.o
+COBJS-$(CONFIG_CMD_UBIFS) += log.o orphan.o recovery.o replay.o
+
+SRCS := $(AOBJS:.o=.S) $(COBJS-y:.o=.c)
+OBJS := $(addprefix $(obj),$(AOBJS) $(COBJS-y))
+
+all: $(LIB) $(AOBJS)
+
+$(LIB): $(obj).depend $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/fs/ubifs/budget.c b/fs/ubifs/budget.c
new file mode 100644
index 0000000..85377ea
--- /dev/null
+++ b/fs/ubifs/budget.c
@@ -0,0 +1,113 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ * Artem Bityutskiy (Битюцкий Ðртём)
+ */
+
+/*
+ * This file implements the budgeting sub-system which is responsible for UBIFS
+ * space management.
+ *
+ * Factors such as compression, wasted space at the ends of LEBs, space in other
+ * journal heads, the effect of updates on the index, and so on, make it
+ * impossible to accurately predict the amount of space needed. Consequently
+ * approximations are used.
+ */
+
+#include "ubifs.h"
+#include <linux/math64.h>
+
+/**
+ * ubifs_calc_min_idx_lebs - calculate amount of eraseblocks for the index.
+ * @c: UBIFS file-system description object
+ *
+ * This function calculates and returns the number of eraseblocks which should
+ * be kept for index usage.
+ */
+int ubifs_calc_min_idx_lebs(struct ubifs_info *c)
+{
+ int idx_lebs, eff_leb_size = c->leb_size - c->max_idx_node_sz;
+ long long idx_size;
+
+ idx_size = c->old_idx_sz + c->budg_idx_growth + c->budg_uncommitted_idx;
+
+ /* And make sure we have thrice the index size of space reserved */
+ idx_size = idx_size + (idx_size << 1);
+
+ /*
+ * We do not maintain 'old_idx_size' as 'old_idx_lebs'/'old_idx_bytes'
+ * pair, nor similarly the two variables for the new index size, so we
+ * have to do this costly 64-bit division on fast-path.
+ */
+ idx_size += eff_leb_size - 1;
+ idx_lebs = div_u64(idx_size, eff_leb_size);
+ /*
+ * The index head is not available for the in-the-gaps method, so add an
+ * extra LEB to compensate.
+ */
+ idx_lebs += 1;
+ if (idx_lebs < MIN_INDEX_LEBS)
+ idx_lebs = MIN_INDEX_LEBS;
+ return idx_lebs;
+}
+
+/**
+ * ubifs_reported_space - calculate reported free space.
+ * @c: the UBIFS file-system description object
+ * @free: amount of free space
+ *
+ * This function calculates amount of free space which will be reported to
+ * user-space. User-space application tend to expect that if the file-system
+ * (e.g., via the 'statfs()' call) reports that it has N bytes available, they
+ * are able to write a file of size N. UBIFS attaches node headers to each data
+ * node and it has to write indexing nodes as well. This introduces additional
+ * overhead, and UBIFS has to report slightly less free space to meet the above
+ * expectations.
+ *
+ * This function assumes free space is made up of uncompressed data nodes and
+ * full index nodes (one per data node, tripled because we always allow enough
+ * space to write the index thrice).
+ *
+ * Note, the calculation is pessimistic, which means that most of the time
+ * UBIFS reports less space than it actually has.
+ */
+long long ubifs_reported_space(const struct ubifs_info *c, long long free)
+{
+ int divisor, factor, f;
+
+ /*
+ * Reported space size is @free * X, where X is UBIFS block size
+ * divided by UBIFS block size + all overhead one data block
+ * introduces. The overhead is the node header + indexing overhead.
+ *
+ * Indexing overhead calculations are based on the following formula:
+ * I = N/(f - 1) + 1, where I - number of indexing nodes, N - number
+ * of data nodes, f - fanout. Because effective UBIFS fanout is twice
+ * as less than maximum fanout, we assume that each data node
+ * introduces 3 * @c->max_idx_node_sz / (@c->fanout/2 - 1) bytes.
+ * Note, the multiplier 3 is because UBIFS reserves thrice as more space
+ * for the index.
+ */
+ f = c->fanout > 3 ? c->fanout >> 1 : 2;
+ factor = UBIFS_BLOCK_SIZE;
+ divisor = UBIFS_MAX_DATA_NODE_SZ;
+ divisor += (c->max_idx_node_sz * 3) / (f - 1);
+ free *= factor;
+ return div_u64(free, divisor);
+}
diff --git a/fs/ubifs/crc16.c b/fs/ubifs/crc16.c
new file mode 100644
index 0000000..443ccf8
--- /dev/null
+++ b/fs/ubifs/crc16.c
@@ -0,0 +1,60 @@
+/*
+ * crc16.c
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/types.h>
+#include "crc16.h"
+
+/** CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */
+u16 const crc16_table[256] = {
+ 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
+ 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
+ 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
+ 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
+ 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
+ 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
+ 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
+ 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
+ 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
+ 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
+ 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
+ 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
+ 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
+ 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
+ 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
+ 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
+ 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
+ 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
+ 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
+ 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
+ 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
+ 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
+ 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
+ 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
+ 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
+ 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
+ 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
+ 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
+ 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
+ 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
+ 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
+ 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
+};
+
+/**
+ * crc16 - compute the CRC-16 for the data buffer
+ * @crc: previous CRC value
+ * @buffer: data pointer
+ * @len: number of bytes in the buffer
+ *
+ * Returns the updated CRC value.
+ */
+u16 crc16(u16 crc, u8 const *buffer, size_t len)
+{
+ while (len--)
+ crc = crc16_byte(crc, *buffer++);
+ return crc;
+}
diff --git a/fs/ubifs/crc16.h b/fs/ubifs/crc16.h
new file mode 100644
index 0000000..9443c08
--- /dev/null
+++ b/fs/ubifs/crc16.h
@@ -0,0 +1,30 @@
+/*
+ * crc16.h - CRC-16 routine
+ *
+ * Implements the standard CRC-16:
+ * Width 16
+ * Poly 0x8005 (x^16 + x^15 + x^2 + 1)
+ * Init 0
+ *
+ * Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#ifndef __CRC16_H
+#define __CRC16_H
+
+#include <linux/types.h>
+
+extern u16 const crc16_table[256];
+
+extern u16 crc16(u16 crc, const u8 *buffer, size_t len);
+
+static inline u16 crc16_byte(u16 crc, const u8 data)
+{
+ return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
+}
+
+#endif /* __CRC16_H */
+
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c
new file mode 100644
index 0000000..6afb883
--- /dev/null
+++ b/fs/ubifs/debug.c
@@ -0,0 +1,156 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Ðртём)
+ * Adrian Hunter
+ */
+
+/*
+ * This file implements most of the debugging stuff which is compiled in only
+ * when it is enabled. But some debugging check functions are implemented in
+ * corresponding subsystem, just because they are closely related and utilize
+ * various local functions of those subsystems.
+ */
+
+#define UBIFS_DBG_PRESERVE_UBI
+
+#include "ubifs.h"
+
+#ifdef CONFIG_UBIFS_FS_DEBUG
+
+DEFINE_SPINLOCK(dbg_lock);
+
+static char dbg_key_buf0[128];
+static char dbg_key_buf1[128];
+
+unsigned int ubifs_msg_flags = UBIFS_MSG_FLAGS_DEFAULT;
+unsigned int ubifs_chk_flags = UBIFS_CHK_FLAGS_DEFAULT;
+unsigned int ubifs_tst_flags;
+
+module_param_named(debug_msgs, ubifs_msg_flags, uint, S_IRUGO | S_IWUSR);
+module_param_named(debug_chks, ubifs_chk_flags, uint, S_IRUGO | S_IWUSR);
+module_param_named(debug_tsts, ubifs_tst_flags, uint, S_IRUGO | S_IWUSR);
+
+MODULE_PARM_DESC(debug_msgs, "Debug message type flags");
+MODULE_PARM_DESC(debug_chks, "Debug check flags");
+MODULE_PARM_DESC(debug_tsts, "Debug special test flags");
+
+static const char *get_key_type(int type)
+{
+ switch (type) {
+ case UBIFS_INO_KEY:
+ return "inode";
+ case UBIFS_DENT_KEY:
+ return "direntry";
+ case UBIFS_XENT_KEY:
+ return "xentry";
+ case UBIFS_DATA_KEY:
+ return "data";
+ case UBIFS_TRUN_KEY:
+ return "truncate";
+ default:
+ return "unknown/invalid key";
+ }
+}
+
+static void sprintf_key(const struct ubifs_info *c, const union ubifs_key *key,
+ char *buffer)
+{
+ char *p = buffer;
+ int type = key_type(c, key);
+
+ if (c->key_fmt == UBIFS_SIMPLE_KEY_FMT) {
+ switch (type) {
+ case UBIFS_INO_KEY:
+ sprintf(p, "(%lu, %s)", (unsigned long)key_inum(c, key),
+ get_key_type(type));
+ break;
+ case UBIFS_DENT_KEY:
+ case UBIFS_XENT_KEY:
+ sprintf(p, "(%lu, %s, %#08x)",
+ (unsigned long)key_inum(c, key),
+ get_key_type(type), key_hash(c, key));
+ break;
+ case UBIFS_DATA_KEY:
+ sprintf(p, "(%lu, %s, %u)",
+ (unsigned long)key_inum(c, key),
+ get_key_type(type), key_block(c, key));
+ break;
+ case UBIFS_TRUN_KEY:
+ sprintf(p, "(%lu, %s)",
+ (unsigned long)key_inum(c, key),
+ get_key_type(type));
+ break;
+ default:
+ sprintf(p, "(bad key type: %#08x, %#08x)",
+ key->u32[0], key->u32[1]);
+ }
+ } else
+ sprintf(p, "bad key format %d", c->key_fmt);
+}
+
+const char *dbg_key_str0(const struct ubifs_info *c, const union ubifs_key *key)
+{
+ /* dbg_lock must be held */
+ sprintf_key(c, key, dbg_key_buf0);
+ return dbg_key_buf0;
+}
+
+const char *dbg_key_str1(const struct ubifs_info *c, const union ubifs_key *key)
+{
+ /* dbg_lock must be held */
+ sprintf_key(c, key, dbg_key_buf1);
+ return dbg_key_buf1;
+}
+
+/**
+ * ubifs_debugging_init - initialize UBIFS debugging.
+ * @c: UBIFS file-system description object
+ *
+ * This function initializes debugging-related data for the file system.
+ * Returns zero in case of success and a negative error code in case of
+ * failure.
+ */
+int ubifs_debugging_init(struct ubifs_info *c)
+{
+ c->dbg = kzalloc(sizeof(struct ubifs_debug_info), GFP_KERNEL);
+ if (!c->dbg)
+ return -ENOMEM;
+
+ c->dbg->buf = vmalloc(c->leb_size);
+ if (!c->dbg->buf)
+ goto out;
+
+ return 0;
+
+out:
+ kfree(c->dbg);
+ return -ENOMEM;
+}
+
+/**
+ * ubifs_debugging_exit - free debugging data.
+ * @c: UBIFS file-system description object
+ */
+void ubifs_debugging_exit(struct ubifs_info *c)
+{
+ vfree(c->dbg->buf);
+ kfree(c->dbg);
+}
+
+#endif /* CONFIG_UBIFS_FS_DEBUG */
diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h
new file mode 100644
index 0000000..62617b6
--- /dev/null
+++ b/fs/ubifs/debug.h
@@ -0,0 +1,392 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Ðртём)
+ * Adrian Hunter
+ */
+
+#ifndef __UBIFS_DEBUG_H__
+#define __UBIFS_DEBUG_H__
+
+#ifdef CONFIG_UBIFS_FS_DEBUG
+
+/**
+ * ubifs_debug_info - per-FS debugging information.
+ * @buf: a buffer of LEB size, used for various purposes
+ * @old_zroot: old index root - used by 'dbg_check_old_index()'
+ * @old_zroot_level: old index root level - used by 'dbg_check_old_index()'
+ * @old_zroot_sqnum: old index root sqnum - used by 'dbg_check_old_index()'
+ * @failure_mode: failure mode for recovery testing
+ * @fail_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls
+ * @fail_timeout: time in jiffies when delay of failure mode expires
+ * @fail_cnt: current number of calls to failure mode I/O functions
+ * @fail_cnt_max: number of calls by which to delay failure mode
+ * @chk_lpt_sz: used by LPT tree size checker
+ * @chk_lpt_sz2: used by LPT tree size checker
+ * @chk_lpt_wastage: used by LPT tree size checker
+ * @chk_lpt_lebs: used by LPT tree size checker
+ * @new_nhead_offs: used by LPT tree size checker
+ * @new_ihead_lnum: used by debugging to check @c->ihead_lnum
+ * @new_ihead_offs: used by debugging to check @c->ihead_offs
+ *
+ * @saved_lst: saved lprops statistics (used by 'dbg_save_space_info()')
+ * @saved_free: saved free space (used by 'dbg_save_space_info()')
+ *
+ * dfs_dir_name: name of debugfs directory containing this file-system's files
+ * dfs_dir: direntry object of the file-system debugfs directory
+ * dfs_dump_lprops: "dump lprops" debugfs knob
+ * dfs_dump_budg: "dump budgeting information" debugfs knob
+ * dfs_dump_tnc: "dump TNC" debugfs knob
+ */
+struct ubifs_debug_info {
+ void *buf;
+ struct ubifs_zbranch old_zroot;
+ int old_zroot_level;
+ unsigned long long old_zroot_sqnum;
+ int failure_mode;
+ int fail_delay;
+ unsigned long fail_timeout;
+ unsigned int fail_cnt;
+ unsigned int fail_cnt_max;
+ long long chk_lpt_sz;
+ long long chk_lpt_sz2;
+ long long chk_lpt_wastage;
+ int chk_lpt_lebs;
+ int new_nhead_offs;
+ int new_ihead_lnum;
+ int new_ihead_offs;
+
+ struct ubifs_lp_stats saved_lst;
+ long long saved_free;
+
+ char dfs_dir_name[100];
+ struct dentry *dfs_dir;
+ struct dentry *dfs_dump_lprops;
+ struct dentry *dfs_dump_budg;
+ struct dentry *dfs_dump_tnc;
+};
+
+#define UBIFS_DBG(op) op
+
+#define ubifs_assert(expr) do { \
+ if (unlikely(!(expr))) { \
+ printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \
+ __func__, __LINE__, 0); \
+ dbg_dump_stack(); \
+ } \
+} while (0)
+
+#define ubifs_assert_cmt_locked(c) do { \
+ if (unlikely(down_write_trylock(&(c)->commit_sem))) { \
+ up_write(&(c)->commit_sem); \
+ printk(KERN_CRIT "commit lock is not locked!\n"); \
+ ubifs_assert(0); \
+ } \
+} while (0)
+
+#define dbg_dump_stack() do { \
+ if (!dbg_failure_mode) \
+ dump_stack(); \
+} while (0)
+
+/* Generic debugging messages */
+#define dbg_msg(fmt, ...) do { \
+ spin_lock(&dbg_lock); \
+ printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n", 0, \
+ __func__, ##__VA_ARGS__); \
+ spin_unlock(&dbg_lock); \
+} while (0)
+
+#define dbg_do_msg(typ, fmt, ...) do { \
+ if (ubifs_msg_flags & typ) \
+ dbg_msg(fmt, ##__VA_ARGS__); \
+} while (0)
+
+#define dbg_err(fmt, ...) do { \
+ spin_lock(&dbg_lock); \
+ ubifs_err(fmt, ##__VA_ARGS__); \
+ spin_unlock(&dbg_lock); \
+} while (0)
+
+const char *dbg_key_str0(const struct ubifs_info *c,
+ const union ubifs_key *key);
+const char *dbg_key_str1(const struct ubifs_info *c,
+ const union ubifs_key *key);
+
+/*
+ * DBGKEY macros require @dbg_lock to be held, which it is in the dbg message
+ * macros.
+ */
+#define DBGKEY(key) dbg_key_str0(c, (key))
+#define DBGKEY1(key) dbg_key_str1(c, (key))
+
+/* General messages */
+#define dbg_gen(fmt, ...) dbg_do_msg(UBIFS_MSG_GEN, fmt, ##__VA_ARGS__)
+
+/* Additional journal messages */
+#define dbg_jnl(fmt, ...) dbg_do_msg(UBIFS_MSG_JNL, fmt, ##__VA_ARGS__)
+
+/* Additional TNC messages */
+#define dbg_tnc(fmt, ...) dbg_do_msg(UBIFS_MSG_TNC, fmt, ##__VA_ARGS__)
+
+/* Additional lprops messages */
+#define dbg_lp(fmt, ...) dbg_do_msg(UBIFS_MSG_LP, fmt, ##__VA_ARGS__)
+
+/* Additional LEB find messages */
+#define dbg_find(fmt, ...) dbg_do_msg(UBIFS_MSG_FIND, fmt, ##__VA_ARGS__)
+
+/* Additional mount messages */
+#define dbg_mnt(fmt, ...) dbg_do_msg(UBIFS_MSG_MNT, fmt, ##__VA_ARGS__)
+
+/* Additional I/O messages */
+#define dbg_io(fmt, ...) dbg_do_msg(UBIFS_MSG_IO, fmt, ##__VA_ARGS__)
+
+/* Additional commit messages */
+#define dbg_cmt(fmt, ...) dbg_do_msg(UBIFS_MSG_CMT, fmt, ##__VA_ARGS__)
+
+/* Additional budgeting messages */
+#define dbg_budg(fmt, ...) dbg_do_msg(UBIFS_MSG_BUDG, fmt, ##__VA_ARGS__)
+
+/* Additional log messages */
+#define dbg_log(fmt, ...) dbg_do_msg(UBIFS_MSG_LOG, fmt, ##__VA_ARGS__)
+
+/* Additional gc messages */
+#define dbg_gc(fmt, ...) dbg_do_msg(UBIFS_MSG_GC, fmt, ##__VA_ARGS__)
+
+/* Additional scan messages */
+#define dbg_scan(fmt, ...) dbg_do_msg(UBIFS_MSG_SCAN, fmt, ##__VA_ARGS__)
+
+/* Additional recovery messages */
+#define dbg_rcvry(fmt, ...) dbg_do_msg(UBIFS_MSG_RCVRY, fmt, ##__VA_ARGS__)
+
+/*
+ * Debugging message type flags (must match msg_type_names in debug.c).
+ *
+ * UBIFS_MSG_GEN: general messages
+ * UBIFS_MSG_JNL: journal messages
+ * UBIFS_MSG_MNT: mount messages
+ * UBIFS_MSG_CMT: commit messages
+ * UBIFS_MSG_FIND: LEB find messages
+ * UBIFS_MSG_BUDG: budgeting messages
+ * UBIFS_MSG_GC: garbage collection messages
+ * UBIFS_MSG_TNC: TNC messages
+ * UBIFS_MSG_LP: lprops messages
+ * UBIFS_MSG_IO: I/O messages
+ * UBIFS_MSG_LOG: log messages
+ * UBIFS_MSG_SCAN: scan messages
+ * UBIFS_MSG_RCVRY: recovery messages
+ */
+enum {
+ UBIFS_MSG_GEN = 0x1,
+ UBIFS_MSG_JNL = 0x2,
+ UBIFS_MSG_MNT = 0x4,
+ UBIFS_MSG_CMT = 0x8,
+ UBIFS_MSG_FIND = 0x10,
+ UBIFS_MSG_BUDG = 0x20,
+ UBIFS_MSG_GC = 0x40,
+ UBIFS_MSG_TNC = 0x80,
+ UBIFS_MSG_LP = 0x100,
+ UBIFS_MSG_IO = 0x200,
+ UBIFS_MSG_LOG = 0x400,
+ UBIFS_MSG_SCAN = 0x800,
+ UBIFS_MSG_RCVRY = 0x1000,
+};
+
+/* Debugging message type flags for each default debug message level */
+#define UBIFS_MSG_LVL_0 0
+#define UBIFS_MSG_LVL_1 0x1
+#define UBIFS_MSG_LVL_2 0x7f
+#define UBIFS_MSG_LVL_3 0xffff
+
+/*
+ * Debugging check flags (must match chk_names in debug.c).
+ *
+ * UBIFS_CHK_GEN: general checks
+ * UBIFS_CHK_TNC: check TNC
+ * UBIFS_CHK_IDX_SZ: check index size
+ * UBIFS_CHK_ORPH: check orphans
+ * UBIFS_CHK_OLD_IDX: check the old index
+ * UBIFS_CHK_LPROPS: check lprops
+ * UBIFS_CHK_FS: check the file-system
+ */
+enum {
+ UBIFS_CHK_GEN = 0x1,
+ UBIFS_CHK_TNC = 0x2,
+ UBIFS_CHK_IDX_SZ = 0x4,
+ UBIFS_CHK_ORPH = 0x8,
+ UBIFS_CHK_OLD_IDX = 0x10,
+ UBIFS_CHK_LPROPS = 0x20,
+ UBIFS_CHK_FS = 0x40,
+};
+
+/*
+ * Special testing flags (must match tst_names in debug.c).
+ *
+ * UBIFS_TST_FORCE_IN_THE_GAPS: force the use of in-the-gaps method
+ * UBIFS_TST_RCVRY: failure mode for recovery testing
+ */
+enum {
+ UBIFS_TST_FORCE_IN_THE_GAPS = 0x2,
+ UBIFS_TST_RCVRY = 0x4,
+};
+
+#if CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 1
+#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_1
+#elif CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 2
+#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_2
+#elif CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 3
+#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_3
+#else
+#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_0
+#endif
+
+#ifdef CONFIG_UBIFS_FS_DEBUG_CHKS
+#define UBIFS_CHK_FLAGS_DEFAULT 0xffffffff
+#else
+#define UBIFS_CHK_FLAGS_DEFAULT 0
+#endif
+
+#define dbg_ntype(type) ""
+#define dbg_cstate(cmt_state) ""
+#define dbg_get_key_dump(c, key) ({})
+#define dbg_dump_inode(c, inode) ({})
+#define dbg_dump_node(c, node) ({})
+#define dbg_dump_budget_req(req) ({})
+#define dbg_dump_lstats(lst) ({})
+#define dbg_dump_budg(c) ({})
+#define dbg_dump_lprop(c, lp) ({})
+#define dbg_dump_lprops(c) ({})
+#define dbg_dump_lpt_info(c) ({})
+#define dbg_dump_leb(c, lnum) ({})
+#define dbg_dump_znode(c, znode) ({})
+#define dbg_dump_heap(c, heap, cat) ({})
+#define dbg_dump_pnode(c, pnode, parent, iip) ({})
+#define dbg_dump_tnc(c) ({})
+#define dbg_dump_index(c) ({})
+
+#define dbg_walk_index(c, leaf_cb, znode_cb, priv) 0
+#define dbg_old_index_check_init(c, zroot) 0
+#define dbg_check_old_index(c, zroot) 0
+#define dbg_check_cats(c) 0
+#define dbg_check_ltab(c) 0
+#define dbg_chk_lpt_free_spc(c) 0
+#define dbg_chk_lpt_sz(c, action, len) 0
+#define dbg_check_synced_i_size(inode) 0
+#define dbg_check_dir_size(c, dir) 0
+#define dbg_check_tnc(c, x) 0
+#define dbg_check_idx_size(c, idx_size) 0
+#define dbg_check_filesystem(c) 0
+#define dbg_check_heap(c, heap, cat, add_pos) ({})
+#define dbg_check_lprops(c) 0
+#define dbg_check_lpt_nodes(c, cnode, row, col) 0
+#define dbg_force_in_the_gaps_enabled 0
+#define dbg_force_in_the_gaps() 0
+#define dbg_failure_mode 0
+#define dbg_failure_mode_registration(c) ({})
+#define dbg_failure_mode_deregistration(c) ({})
+
+int ubifs_debugging_init(struct ubifs_info *c);
+void ubifs_debugging_exit(struct ubifs_info *c);
+
+#else /* !CONFIG_UBIFS_FS_DEBUG */
+
+#define UBIFS_DBG(op)
+
+/* Use "if (0)" to make compiler check arguments even if debugging is off */
+#define ubifs_assert(expr) do { \
+ if (0 && (expr)) \
+ printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \
+ __func__, __LINE__, 0); \
+} while (0)
+
+#define dbg_err(fmt, ...) do { \
+ if (0) \
+ ubifs_err(fmt, ##__VA_ARGS__); \
+} while (0)
+
+#define dbg_msg(fmt, ...) do { \
+ if (0) \
+ printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n", \
+ 0, __func__, ##__VA_ARGS__); \
+} while (0)
+
+#define dbg_dump_stack()
+#define ubifs_assert_cmt_locked(c)
+
+#define dbg_gen(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_jnl(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_tnc(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_lp(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_find(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_mnt(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_io(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_cmt(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_budg(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_log(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_gc(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_scan(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_rcvry(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+
+#define DBGKEY(key) ((char *)(key))
+#define DBGKEY1(key) ((char *)(key))
+
+#define ubifs_debugging_init(c) 0
+#define ubifs_debugging_exit(c) ({})
+
+#define dbg_ntype(type) ""
+#define dbg_cstate(cmt_state) ""
+#define dbg_get_key_dump(c, key) ({})
+#define dbg_dump_inode(c, inode) ({})
+#define dbg_dump_node(c, node) ({})
+#define dbg_dump_budget_req(req) ({})
+#define dbg_dump_lstats(lst) ({})
+#define dbg_dump_budg(c) ({})
+#define dbg_dump_lprop(c, lp) ({})
+#define dbg_dump_lprops(c) ({})
+#define dbg_dump_lpt_info(c) ({})
+#define dbg_dump_leb(c, lnum) ({})
+#define dbg_dump_znode(c, znode) ({})
+#define dbg_dump_heap(c, heap, cat) ({})
+#define dbg_dump_pnode(c, pnode, parent, iip) ({})
+#define dbg_dump_tnc(c) ({})
+#define dbg_dump_index(c) ({})
+
+#define dbg_walk_index(c, leaf_cb, znode_cb, priv) 0
+#define dbg_old_index_check_init(c, zroot) 0
+#define dbg_check_old_index(c, zroot) 0
+#define dbg_check_cats(c) 0
+#define dbg_check_ltab(c) 0
+#define dbg_chk_lpt_free_spc(c) 0
+#define dbg_chk_lpt_sz(c, action, len) 0
+#define dbg_check_synced_i_size(inode) 0
+#define dbg_check_dir_size(c, dir) 0
+#define dbg_check_tnc(c, x) 0
+#define dbg_check_idx_size(c, idx_size) 0
+#define dbg_check_filesystem(c) 0
+#define dbg_check_heap(c, heap, cat, add_pos) ({})
+#define dbg_check_lprops(c) 0
+#define dbg_check_lpt_nodes(c, cnode, row, col) 0
+#define dbg_force_in_the_gaps_enabled 0
+#define dbg_force_in_the_gaps() 0
+#define dbg_failure_mode 0
+#define dbg_failure_mode_registration(c) ({})
+#define dbg_failure_mode_deregistration(c) ({})
+
+#endif /* !CONFIG_UBIFS_FS_DEBUG */
+
+#endif /* !__UBIFS_DEBUG_H__ */
diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c
new file mode 100644
index 0000000..aae5c65
--- /dev/null
+++ b/fs/ubifs/io.c
@@ -0,0 +1,316 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ * Copyright (C) 2006, 2007 University of Szeged, Hungary
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Ðртём)
+ * Adrian Hunter
+ * Zoltan Sogor
+ */
+
+/*
+ * This file implements UBIFS I/O subsystem which provides various I/O-related
+ * helper functions (reading/writing/checking/validating nodes) and implements
+ * write-buffering support. Write buffers help to save space which otherwise
+ * would have been wasted for padding to the nearest minimal I/O unit boundary.
+ * Instead, data first goes to the write-buffer and is flushed when the
+ * buffer is full or when it is not used for some time (by timer). This is
+ * similar to the mechanism is used by JFFS2.
+ *
+ * Write-buffers are defined by 'struct ubifs_wbuf' objects and protected by
+ * mutexes defined inside these objects. Since sometimes upper-level code
+ * has to lock the write-buffer (e.g. journal space reservation code), many
+ * functions related to write-buffers have "nolock" suffix which means that the
+ * caller has to lock the write-buffer before calling this function.
+ *
+ * UBIFS stores nodes at 64 bit-aligned addresses. If the node length is not
+ * aligned, UBIFS starts the next node from the aligned address, and the padded
+ * bytes may contain any rubbish. In other words, UBIFS does not put padding
+ * bytes in those small gaps. Common headers of nodes store real node lengths,
+ * not aligned lengths. Indexing nodes also store real lengths in branches.
+ *
+ * UBIFS uses padding when it pads to the next min. I/O unit. In this case it
+ * uses padding nodes or padding bytes, if the padding node does not fit.
+ *
+ * All UBIFS nodes are protected by CRC checksums and UBIFS checks all nodes
+ * every time they are read from the flash media.
+ */
+
+#include "ubifs.h"
+
+/**
+ * ubifs_ro_mode - switch UBIFS to read read-only mode.
+ * @c: UBIFS file-system description object
+ * @err: error code which is the reason of switching to R/O mode
+ */
+void ubifs_ro_mode(struct ubifs_info *c, int err)
+{
+ if (!c->ro_media) {
+ c->ro_media = 1;
+ c->no_chk_data_crc = 0;
+ ubifs_warn("switched to read-only mode, error %d", err);
+ dbg_dump_stack();
+ }
+}
+
+/**
+ * ubifs_check_node - check node.
+ * @c: UBIFS file-system description object
+ * @buf: node to check
+ * @lnum: logical eraseblock number
+ * @offs: offset within the logical eraseblock
+ * @quiet: print no messages
+ * @must_chk_crc: indicates whether to always check the CRC
+ *
+ * This function checks node magic number and CRC checksum. This function also
+ * validates node length to prevent UBIFS from becoming crazy when an attacker
+ * feeds it a file-system image with incorrect nodes. For example, too large
+ * node length in the common header could cause UBIFS to read memory outside of
+ * allocated buffer when checking the CRC checksum.
+ *
+ * This function may skip data nodes CRC checking if @c->no_chk_data_crc is
+ * true, which is controlled by corresponding UBIFS mount option. However, if
+ * @must_chk_crc is true, then @c->no_chk_data_crc is ignored and CRC is
+ * checked. Similarly, if @c->always_chk_crc is true, @c->no_chk_data_crc is
+ * ignored and CRC is checked.
+ *
+ * This function returns zero in case of success and %-EUCLEAN in case of bad
+ * CRC or magic.
+ */
+int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
+ int offs, int quiet, int must_chk_crc)
+{
+ int err = -EINVAL, type, node_len;
+ uint32_t crc, node_crc, magic;
+ const struct ubifs_ch *ch = buf;
+
+ ubifs_assert(lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
+ ubifs_assert(!(offs & 7) && offs < c->leb_size);
+
+ magic = le32_to_cpu(ch->magic);
+ if (magic != UBIFS_NODE_MAGIC) {
+ if (!quiet)
+ ubifs_err("bad magic %#08x, expected %#08x",
+ magic, UBIFS_NODE_MAGIC);
+ err = -EUCLEAN;
+ goto out;
+ }
+
+ type = ch->node_type;
+ if (type < 0 || type >= UBIFS_NODE_TYPES_CNT) {
+ if (!quiet)
+ ubifs_err("bad node type %d", type);
+ goto out;
+ }
+
+ node_len = le32_to_cpu(ch->len);
+ if (node_len + offs > c->leb_size)
+ goto out_len;
+
+ if (c->ranges[type].max_len == 0) {
+ if (node_len != c->ranges[type].len)
+ goto out_len;
+ } else if (node_len < c->ranges[type].min_len ||
+ node_len > c->ranges[type].max_len)
+ goto out_len;
+
+ if (!must_chk_crc && type == UBIFS_DATA_NODE && !c->always_chk_crc &&
+ c->no_chk_data_crc)
+ return 0;
+
+ crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
+ node_crc = le32_to_cpu(ch->crc);
+ if (crc != node_crc) {
+ if (!quiet)
+ ubifs_err("bad CRC: calculated %#08x, read %#08x",
+ crc, node_crc);
+ err = -EUCLEAN;
+ goto out;
+ }
+
+ return 0;
+
+out_len:
+ if (!quiet)
+ ubifs_err("bad node length %d", node_len);
+out:
+ if (!quiet) {
+ ubifs_err("bad node at LEB %d:%d", lnum, offs);
+ dbg_dump_node(c, buf);
+ dbg_dump_stack();
+ }
+ return err;
+}
+
+/**
+ * ubifs_pad - pad flash space.
+ * @c: UBIFS file-system description object
+ * @buf: buffer to put padding to
+ * @pad: how many bytes to pad
+ *
+ * The flash media obliges us to write only in chunks of %c->min_io_size and
+ * when we have to write less data we add padding node to the write-buffer and
+ * pad it to the next minimal I/O unit's boundary. Padding nodes help when the
+ * media is being scanned. If the amount of wasted space is not enough to fit a
+ * padding node which takes %UBIFS_PAD_NODE_SZ bytes, we write padding bytes
+ * pattern (%UBIFS_PADDING_BYTE).
+ *
+ * Padding nodes are also used to fill gaps when the "commit-in-gaps" method is
+ * used.
+ */
+void ubifs_pad(const struct ubifs_info *c, void *buf, int pad)
+{
+ uint32_t crc;
+
+ ubifs_assert(pad >= 0 && !(pad & 7));
+
+ if (pad >= UBIFS_PAD_NODE_SZ) {
+ struct ubifs_ch *ch = buf;
+ struct ubifs_pad_node *pad_node = buf;
+
+ ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC);
+ ch->node_type = UBIFS_PAD_NODE;
+ ch->group_type = UBIFS_NO_NODE_GROUP;
+ ch->padding[0] = ch->padding[1] = 0;
+ ch->sqnum = 0;
+ ch->len = cpu_to_le32(UBIFS_PAD_NODE_SZ);
+ pad -= UBIFS_PAD_NODE_SZ;
+ pad_node->pad_len = cpu_to_le32(pad);
+ crc = crc32(UBIFS_CRC32_INIT, buf + 8, UBIFS_PAD_NODE_SZ - 8);
+ ch->crc = cpu_to_le32(crc);
+ memset(buf + UBIFS_PAD_NODE_SZ, 0, pad);
+ } else if (pad > 0)
+ /* Too little space, padding node won't fit */
+ memset(buf, UBIFS_PADDING_BYTE, pad);
+}
+
+/**
+ * next_sqnum - get next sequence number.
+ * @c: UBIFS file-system description object
+ */
+static unsigned long long next_sqnum(struct ubifs_info *c)
+{
+ unsigned long long sqnum;
+
+ spin_lock(&c->cnt_lock);
+ sqnum = ++c->max_sqnum;
+ spin_unlock(&c->cnt_lock);
+
+ if (unlikely(sqnum >= SQNUM_WARN_WATERMARK)) {
+ if (sqnum >= SQNUM_WATERMARK) {
+ ubifs_err("sequence number overflow %llu, end of life",
+ sqnum);
+ ubifs_ro_mode(c, -EINVAL);
+ }
+ ubifs_warn("running out of sequence numbers, end of life soon");
+ }
+
+ return sqnum;
+}
+
+/**
+ * ubifs_prepare_node - prepare node to be written to flash.
+ * @c: UBIFS file-system description object
+ * @node: the node to pad
+ * @len: node length
+ * @pad: if the buffer has to be padded
+ *
+ * This function prepares node at @node to be written to the media - it
+ * calculates node CRC, fills the common header, and adds proper padding up to
+ * the next minimum I/O unit if @pad is not zero.
+ */
+void ubifs_prepare_node(struct ubifs_info *c, void *node, int len, int pad)
+{
+ uint32_t crc;
+ struct ubifs_ch *ch = node;
+ unsigned long long sqnum = next_sqnum(c);
+
+ ubifs_assert(len >= UBIFS_CH_SZ);
+
+ ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC);
+ ch->len = cpu_to_le32(len);
+ ch->group_type = UBIFS_NO_NODE_GROUP;
+ ch->sqnum = cpu_to_le64(sqnum);
+ ch->padding[0] = ch->padding[1] = 0;
+ crc = crc32(UBIFS_CRC32_INIT, node + 8, len - 8);
+ ch->crc = cpu_to_le32(crc);
+
+ if (pad) {
+ len = ALIGN(len, 8);
+ pad = ALIGN(len, c->min_io_size) - len;
+ ubifs_pad(c, node + len, pad);
+ }
+}
+
+/**
+ * ubifs_read_node - read node.
+ * @c: UBIFS file-system description object
+ * @buf: buffer to read to
+ * @type: node type
+ * @len: node length (not aligned)
+ * @lnum: logical eraseblock number
+ * @offs: offset within the logical eraseblock
+ *
+ * This function reads a node of known type and and length, checks it and
+ * stores in @buf. Returns zero in case of success, %-EUCLEAN if CRC mismatched
+ * and a negative error code in case of failure.
+ */
+int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
+ int lnum, int offs)
+{
+ int err, l;
+ struct ubifs_ch *ch = buf;
+
+ dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len);
+ ubifs_assert(lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
+ ubifs_assert(len >= UBIFS_CH_SZ && offs + len <= c->leb_size);
+ ubifs_assert(!(offs & 7) && offs < c->leb_size);
+ ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT);
+
+ err = ubi_read(c->ubi, lnum, buf, offs, len);
+ if (err && err != -EBADMSG) {
+ ubifs_err("cannot read node %d from LEB %d:%d, error %d",
+ type, lnum, offs, err);
+ return err;
+ }
+
+ if (type != ch->node_type) {
+ ubifs_err("bad node type (%d but expected %d)",
+ ch->node_type, type);
+ goto out;
+ }
+
+ err = ubifs_check_node(c, buf, lnum, offs, 0, 0);
+ if (err) {
+ ubifs_err("expected node type %d", type);
+ return err;
+ }
+
+ l = le32_to_cpu(ch->len);
+ if (l != len) {
+ ubifs_err("bad node length %d, expected %d", l, len);
+ goto out;
+ }
+
+ return 0;
+
+out:
+ ubifs_err("bad node at LEB %d:%d", lnum, offs);
+ dbg_dump_node(c, buf);
+ dbg_dump_stack();
+ return -EINVAL;
+}
diff --git a/fs/ubifs/key.h b/fs/ubifs/key.h
new file mode 100644
index 0000000..efb3430
--- /dev/null
+++ b/fs/ubifs/key.h
@@ -0,0 +1,557 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Ðртём)
+ * Adrian Hunter
+ */
+
+/*
+ * This header contains various key-related definitions and helper function.
+ * UBIFS allows several key schemes, so we access key fields only via these
+ * helpers. At the moment only one key scheme is supported.
+ *
+ * Simple key scheme
+ * ~~~~~~~~~~~~~~~~~
+ *
+ * Keys are 64-bits long. First 32-bits are inode number (parent inode number
+ * in case of direntry key). Next 3 bits are node type. The last 29 bits are
+ * 4KiB offset in case of inode node, and direntry hash in case of a direntry
+ * node. We use "r5" hash borrowed from reiserfs.
+ */
+
+#ifndef __UBIFS_KEY_H__
+#define __UBIFS_KEY_H__
+
+/**
+ * key_mask_hash - mask a valid hash value.
+ * @val: value to be masked
+ *
+ * We use hash values as offset in directories, so values %0 and %1 are
+ * reserved for "." and "..". %2 is reserved for "end of readdir" marker. This
+ * function makes sure the reserved values are not used.
+ */
+static inline uint32_t key_mask_hash(uint32_t hash)
+{
+ hash &= UBIFS_S_KEY_HASH_MASK;
+ if (unlikely(hash <= 2))
+ hash += 3;
+ return hash;
+}
+
+/**
+ * key_r5_hash - R5 hash function (borrowed from reiserfs).
+ * @s: direntry name
+ * @len: name length
+ */
+static inline uint32_t key_r5_hash(const char *s, int len)
+{
+ uint32_t a = 0;
+ const signed char *str = (const signed char *)s;
+
+ while (*str) {
+ a += *str << 4;
+ a += *str >> 4;
+ a *= 11;
+ str++;
+ }
+
+ return key_mask_hash(a);
+}
+
+/**
+ * key_test_hash - testing hash function.
+ * @str: direntry name
+ * @len: name length
+ */
+static inline uint32_t key_test_hash(const char *str, int len)
+{
+ uint32_t a = 0;
+
+ len = min_t(uint32_t, len, 4);
+ memcpy(&a, str, len);
+ return key_mask_hash(a);
+}
+
+/**
+ * ino_key_init - initialize inode key.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: inode number
+ */
+static inline void ino_key_init(const struct ubifs_info *c,
+ union ubifs_key *key, ino_t inum)
+{
+ key->u32[0] = inum;
+ key->u32[1] = UBIFS_INO_KEY << UBIFS_S_KEY_BLOCK_BITS;
+}
+
+/**
+ * ino_key_init_flash - initialize on-flash inode key.
+ * @c: UBIFS file-system description object
+ * @k: key to initialize
+ * @inum: inode number
+ */
+static inline void ino_key_init_flash(const struct ubifs_info *c, void *k,
+ ino_t inum)
+{
+ union ubifs_key *key = k;
+
+ key->j32[0] = cpu_to_le32(inum);
+ key->j32[1] = cpu_to_le32(UBIFS_INO_KEY << UBIFS_S_KEY_BLOCK_BITS);
+ memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8);
+}
+
+/**
+ * lowest_ino_key - get the lowest possible inode key.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: inode number
+ */
+static inline void lowest_ino_key(const struct ubifs_info *c,
+ union ubifs_key *key, ino_t inum)
+{
+ key->u32[0] = inum;
+ key->u32[1] = 0;
+}
+
+/**
+ * highest_ino_key - get the highest possible inode key.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: inode number
+ */
+static inline void highest_ino_key(const struct ubifs_info *c,
+ union ubifs_key *key, ino_t inum)
+{
+ key->u32[0] = inum;
+ key->u32[1] = 0xffffffff;
+}
+
+/**
+ * dent_key_init - initialize directory entry key.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: parent inode number
+ * @nm: direntry name and length
+ */
+static inline void dent_key_init(const struct ubifs_info *c,
+ union ubifs_key *key, ino_t inum,
+ const struct qstr *nm)
+{
+ uint32_t hash = c->key_hash(nm->name, nm->len);
+
+ ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
+ key->u32[0] = inum;
+ key->u32[1] = hash | (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS);
+}
+
+/**
+ * dent_key_init_hash - initialize directory entry key without re-calculating
+ * hash function.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: parent inode number
+ * @hash: direntry name hash
+ */
+static inline void dent_key_init_hash(const struct ubifs_info *c,
+ union ubifs_key *key, ino_t inum,
+ uint32_t hash)
+{
+ ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
+ key->u32[0] = inum;
+ key->u32[1] = hash | (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS);
+}
+
+/**
+ * dent_key_init_flash - initialize on-flash directory entry key.
+ * @c: UBIFS file-system description object
+ * @k: key to initialize
+ * @inum: parent inode number
+ * @nm: direntry name and length
+ */
+static inline void dent_key_init_flash(const struct ubifs_info *c, void *k,
+ ino_t inum, const struct qstr *nm)
+{
+ union ubifs_key *key = k;
+ uint32_t hash = c->key_hash(nm->name, nm->len);
+
+ ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
+ key->j32[0] = cpu_to_le32(inum);
+ key->j32[1] = cpu_to_le32(hash |
+ (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS));
+ memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8);
+}
+
+/**
+ * lowest_dent_key - get the lowest possible directory entry key.
+ * @c: UBIFS file-system description object
+ * @key: where to store the lowest key
+ * @inum: parent inode number
+ */
+static inline void lowest_dent_key(const struct ubifs_info *c,
+ union ubifs_key *key, ino_t inum)
+{
+ key->u32[0] = inum;
+ key->u32[1] = UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS;
+}
+
+/**
+ * xent_key_init - initialize extended attribute entry key.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: host inode number
+ * @nm: extended attribute entry name and length
+ */
+static inline void xent_key_init(const struct ubifs_info *c,
+ union ubifs_key *key, ino_t inum,
+ const struct qstr *nm)
+{
+ uint32_t hash = c->key_hash(nm->name, nm->len);
+
+ ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
+ key->u32[0] = inum;
+ key->u32[1] = hash | (UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS);
+}
+
+/**
+ * xent_key_init_hash - initialize extended attribute entry key without
+ * re-calculating hash function.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: host inode number
+ * @hash: extended attribute entry name hash
+ */
+static inline void xent_key_init_hash(const struct ubifs_info *c,
+ union ubifs_key *key, ino_t inum,
+ uint32_t hash)
+{
+ ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
+ key->u32[0] = inum;
+ key->u32[1] = hash | (UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS);
+}
+
+/**
+ * xent_key_init_flash - initialize on-flash extended attribute entry key.
+ * @c: UBIFS file-system description object
+ * @k: key to initialize
+ * @inum: host inode number
+ * @nm: extended attribute entry name and length
+ */
+static inline void xent_key_init_flash(const struct ubifs_info *c, void *k,
+ ino_t inum, const struct qstr *nm)
+{
+ union ubifs_key *key = k;
+ uint32_t hash = c->key_hash(nm->name, nm->len);
+
+ ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
+ key->j32[0] = cpu_to_le32(inum);
+ key->j32[1] = cpu_to_le32(hash |
+ (UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS));
+ memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8);
+}
+
+/**
+ * lowest_xent_key - get the lowest possible extended attribute entry key.
+ * @c: UBIFS file-system description object
+ * @key: where to store the lowest key
+ * @inum: host inode number
+ */
+static inline void lowest_xent_key(const struct ubifs_info *c,
+ union ubifs_key *key, ino_t inum)
+{
+ key->u32[0] = inum;
+ key->u32[1] = UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS;
+}
+
+/**
+ * data_key_init - initialize data key.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: inode number
+ * @block: block number
+ */
+static inline void data_key_init(const struct ubifs_info *c,
+ union ubifs_key *key, ino_t inum,
+ unsigned int block)
+{
+ ubifs_assert(!(block & ~UBIFS_S_KEY_BLOCK_MASK));
+ key->u32[0] = inum;
+ key->u32[1] = block | (UBIFS_DATA_KEY << UBIFS_S_KEY_BLOCK_BITS);
+}
+
+/**
+ * data_key_init_flash - initialize on-flash data key.
+ * @c: UBIFS file-system description object
+ * @k: key to initialize
+ * @inum: inode number
+ * @block: block number
+ */
+static inline void data_key_init_flash(const struct ubifs_info *c, void *k,
+ ino_t inum, unsigned int block)
+{
+ union ubifs_key *key = k;
+
+ ubifs_assert(!(block & ~UBIFS_S_KEY_BLOCK_MASK));
+ key->j32[0] = cpu_to_le32(inum);
+ key->j32[1] = cpu_to_le32(block |
+ (UBIFS_DATA_KEY << UBIFS_S_KEY_BLOCK_BITS));
+ memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8);
+}
+
+/**
+ * trun_key_init - initialize truncation node key.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: inode number
+ *
+ * Note, UBIFS does not have truncation keys on the media and this function is
+ * only used for purposes of replay.
+ */
+static inline void trun_key_init(const struct ubifs_info *c,
+ union ubifs_key *key, ino_t inum)
+{
+ key->u32[0] = inum;
+ key->u32[1] = UBIFS_TRUN_KEY << UBIFS_S_KEY_BLOCK_BITS;
+}
+
+/**
+ * key_type - get key type.
+ * @c: UBIFS file-system description object
+ * @key: key to get type of
+ */
+static inline int key_type(const struct ubifs_info *c,
+ const union ubifs_key *key)
+{
+ return key->u32[1] >> UBIFS_S_KEY_BLOCK_BITS;
+}
+
+/**
+ * key_type_flash - get type of a on-flash formatted key.
+ * @c: UBIFS file-system description object
+ * @k: key to get type of
+ */
+static inline int key_type_flash(const struct ubifs_info *c, const void *k)
+{
+ const union ubifs_key *key = k;
+
+ return le32_to_cpu(key->j32[1]) >> UBIFS_S_KEY_BLOCK_BITS;
+}
+
+/**
+ * key_inum - fetch inode number from key.
+ * @c: UBIFS file-system description object
+ * @k: key to fetch inode number from
+ */
+static inline ino_t key_inum(const struct ubifs_info *c, const void *k)
+{
+ const union ubifs_key *key = k;
+
+ return key->u32[0];
+}
+
+/**
+ * key_inum_flash - fetch inode number from an on-flash formatted key.
+ * @c: UBIFS file-system description object
+ * @k: key to fetch inode number from
+ */
+static inline ino_t key_inum_flash(const struct ubifs_info *c, const void *k)
+{
+ const union ubifs_key *key = k;
+
+ return le32_to_cpu(key->j32[0]);
+}
+
+/**
+ * key_hash - get directory entry hash.
+ * @c: UBIFS file-system description object
+ * @key: the key to get hash from
+ */
+static inline int key_hash(const struct ubifs_info *c,
+ const union ubifs_key *key)
+{
+ return key->u32[1] & UBIFS_S_KEY_HASH_MASK;
+}
+
+/**
+ * key_hash_flash - get directory entry hash from an on-flash formatted key.
+ * @c: UBIFS file-system description object
+ * @k: the key to get hash from
+ */
+static inline int key_hash_flash(const struct ubifs_info *c, const void *k)
+{
+ const union ubifs_key *key = k;
+
+ return le32_to_cpu(key->j32[1]) & UBIFS_S_KEY_HASH_MASK;
+}
+
+/**
+ * key_block - get data block number.
+ * @c: UBIFS file-system description object
+ * @key: the key to get the block number from
+ */
+static inline unsigned int key_block(const struct ubifs_info *c,
+ const union ubifs_key *key)
+{
+ return key->u32[1] & UBIFS_S_KEY_BLOCK_MASK;
+}
+
+/**
+ * key_block_flash - get data block number from an on-flash formatted key.
+ * @c: UBIFS file-system description object
+ * @k: the key to get the block number from
+ */
+static inline unsigned int key_block_flash(const struct ubifs_info *c,
+ const void *k)
+{
+ const union ubifs_key *key = k;
+
+ return le32_to_cpu(key->j32[1]) & UBIFS_S_KEY_BLOCK_MASK;
+}
+
+/**
+ * key_read - transform a key to in-memory format.
+ * @c: UBIFS file-system description object
+ * @from: the key to transform
+ * @to: the key to store the result
+ */
+static inline void key_read(const struct ubifs_info *c, const void *from,
+ union ubifs_key *to)
+{
+ const union ubifs_key *f = from;
+
+ to->u32[0] = le32_to_cpu(f->j32[0]);
+ to->u32[1] = le32_to_cpu(f->j32[1]);
+}
+
+/**
+ * key_write - transform a key from in-memory format.
+ * @c: UBIFS file-system description object
+ * @from: the key to transform
+ * @to: the key to store the result
+ */
+static inline void key_write(const struct ubifs_info *c,
+ const union ubifs_key *from, void *to)
+{
+ union ubifs_key *t = to;
+
+ t->j32[0] = cpu_to_le32(from->u32[0]);
+ t->j32[1] = cpu_to_le32(from->u32[1]);
+ memset(to + 8, 0, UBIFS_MAX_KEY_LEN - 8);
+}
+
+/**
+ * key_write_idx - transform a key from in-memory format for the index.
+ * @c: UBIFS file-system description object
+ * @from: the key to transform
+ * @to: the key to store the result
+ */
+static inline void key_write_idx(const struct ubifs_info *c,
+ const union ubifs_key *from, void *to)
+{
+ union ubifs_key *t = to;
+
+ t->j32[0] = cpu_to_le32(from->u32[0]);
+ t->j32[1] = cpu_to_le32(from->u32[1]);
+}
+
+/**
+ * key_copy - copy a key.
+ * @c: UBIFS file-system description object
+ * @from: the key to copy from
+ * @to: the key to copy to
+ */
+static inline void key_copy(const struct ubifs_info *c,
+ const union ubifs_key *from, union ubifs_key *to)
+{
+ to->u64[0] = from->u64[0];
+}
+
+/**
+ * keys_cmp - compare keys.
+ * @c: UBIFS file-system description object
+ * @key1: the first key to compare
+ * @key2: the second key to compare
+ *
+ * This function compares 2 keys and returns %-1 if @key1 is less than
+ * @key2, %0 if the keys are equivalent and %1 if @key1 is greater than @key2.
+ */
+static inline int keys_cmp(const struct ubifs_info *c,
+ const union ubifs_key *key1,
+ const union ubifs_key *key2)
+{
+ if (key1->u32[0] < key2->u32[0])
+ return -1;
+ if (key1->u32[0] > key2->u32[0])
+ return 1;
+ if (key1->u32[1] < key2->u32[1])
+ return -1;
+ if (key1->u32[1] > key2->u32[1])
+ return 1;
+
+ return 0;
+}
+
+/**
+ * keys_eq - determine if keys are equivalent.
+ * @c: UBIFS file-system description object
+ * @key1: the first key to compare
+ * @key2: the second key to compare
+ *
+ * This function compares 2 keys and returns %1 if @key1 is equal to @key2 and
+ * %0 if not.
+ */
+static inline int keys_eq(const struct ubifs_info *c,
+ const union ubifs_key *key1,
+ const union ubifs_key *key2)
+{
+ if (key1->u32[0] != key2->u32[0])
+ return 0;
+ if (key1->u32[1] != key2->u32[1])
+ return 0;
+ return 1;
+}
+
+/**
+ * is_hash_key - is a key vulnerable to hash collisions.
+ * @c: UBIFS file-system description object
+ * @key: key
+ *
+ * This function returns %1 if @key is a hashed key or %0 otherwise.
+ */
+static inline int is_hash_key(const struct ubifs_info *c,
+ const union ubifs_key *key)
+{
+ int type = key_type(c, key);
+
+ return type == UBIFS_DENT_KEY || type == UBIFS_XENT_KEY;
+}
+
+/**
+ * key_max_inode_size - get maximum file size allowed by current key format.
+ * @c: UBIFS file-system description object
+ */
+static inline unsigned long long key_max_inode_size(const struct ubifs_info *c)
+{
+ switch (c->key_fmt) {
+ case UBIFS_SIMPLE_KEY_FMT:
+ return (1ULL << UBIFS_S_KEY_BLOCK_BITS) * UBIFS_BLOCK_SIZE;
+ default:
+ return 0;
+ }
+}
+#endif /* !__UBIFS_KEY_H__ */
diff --git a/fs/ubifs/log.c b/fs/ubifs/log.c
new file mode 100644
index 0000000..68a9bd9
--- /dev/null
+++ b/fs/ubifs/log.c
@@ -0,0 +1,104 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Ðртём)
+ * Adrian Hunter
+ */
+
+/*
+ * This file is a part of UBIFS journal implementation and contains various
+ * functions which manipulate the log. The log is a fixed area on the flash
+ * which does not contain any data but refers to buds. The log is a part of the
+ * journal.
+ */
+
+#include "ubifs.h"
+
+/**
+ * ubifs_search_bud - search bud LEB.
+ * @c: UBIFS file-system description object
+ * @lnum: logical eraseblock number to search
+ *
+ * This function searches bud LEB @lnum. Returns bud description object in case
+ * of success and %NULL if there is no bud with this LEB number.
+ */
+struct ubifs_bud *ubifs_search_bud(struct ubifs_info *c, int lnum)
+{
+ struct rb_node *p;
+ struct ubifs_bud *bud;
+
+ spin_lock(&c->buds_lock);
+ p = c->buds.rb_node;
+ while (p) {
+ bud = rb_entry(p, struct ubifs_bud, rb);
+ if (lnum < bud->lnum)
+ p = p->rb_left;
+ else if (lnum > bud->lnum)
+ p = p->rb_right;
+ else {
+ spin_unlock(&c->buds_lock);
+ return bud;
+ }
+ }
+ spin_unlock(&c->buds_lock);
+ return NULL;
+}
+
+/**
+ * ubifs_add_bud - add bud LEB to the tree of buds and its journal head list.
+ * @c: UBIFS file-system description object
+ * @bud: the bud to add
+ */
+void ubifs_add_bud(struct ubifs_info *c, struct ubifs_bud *bud)
+{
+ struct rb_node **p, *parent = NULL;
+ struct ubifs_bud *b;
+ struct ubifs_jhead *jhead;
+
+ spin_lock(&c->buds_lock);
+ p = &c->buds.rb_node;
+ while (*p) {
+ parent = *p;
+ b = rb_entry(parent, struct ubifs_bud, rb);
+ ubifs_assert(bud->lnum != b->lnum);
+ if (bud->lnum < b->lnum)
+ p = &(*p)->rb_left;
+ else
+ p = &(*p)->rb_right;
+ }
+
+ rb_link_node(&bud->rb, parent, p);
+ rb_insert_color(&bud->rb, &c->buds);
+ if (c->jheads) {
+ jhead = &c->jheads[bud->jhead];
+ list_add_tail(&bud->list, &jhead->buds_list);
+ } else
+ ubifs_assert(c->replaying && (c->vfs_sb->s_flags & MS_RDONLY));
+
+ /*
+ * Note, although this is a new bud, we anyway account this space now,
+ * before any data has been written to it, because this is about to
+ * guarantee fixed mount time, and this bud will anyway be read and
+ * scanned.
+ */
+ c->bud_bytes += c->leb_size - bud->start;
+
+ dbg_log("LEB %d:%d, jhead %d, bud_bytes %lld", bud->lnum,
+ bud->start, bud->jhead, c->bud_bytes);
+ spin_unlock(&c->buds_lock);
+}
diff --git a/fs/ubifs/lprops.c b/fs/ubifs/lprops.c
new file mode 100644
index 0000000..8ce4949
--- /dev/null
+++ b/fs/ubifs/lprops.c
@@ -0,0 +1,842 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ * Artem Bityutskiy (Битюцкий Ðртём)
+ */
+
+/*
+ * This file implements the functions that access LEB properties and their
+ * categories. LEBs are categorized based on the needs of UBIFS, and the
+ * categories are stored as either heaps or lists to provide a fast way of
+ * finding a LEB in a particular category. For example, UBIFS may need to find
+ * an empty LEB for the journal, or a very dirty LEB for garbage collection.
+ */
+
+#include "ubifs.h"
+
+/**
+ * get_heap_comp_val - get the LEB properties value for heap comparisons.
+ * @lprops: LEB properties
+ * @cat: LEB category
+ */
+static int get_heap_comp_val(struct ubifs_lprops *lprops, int cat)
+{
+ switch (cat) {
+ case LPROPS_FREE:
+ return lprops->free;
+ case LPROPS_DIRTY_IDX:
+ return lprops->free + lprops->dirty;
+ default:
+ return lprops->dirty;
+ }
+}
+
+/**
+ * move_up_lpt_heap - move a new heap entry up as far as possible.
+ * @c: UBIFS file-system description object
+ * @heap: LEB category heap
+ * @lprops: LEB properties to move
+ * @cat: LEB category
+ *
+ * New entries to a heap are added at the bottom and then moved up until the
+ * parent's value is greater. In the case of LPT's category heaps, the value
+ * is either the amount of free space or the amount of dirty space, depending
+ * on the category.
+ */
+static void move_up_lpt_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap,
+ struct ubifs_lprops *lprops, int cat)
+{
+ int val1, val2, hpos;
+
+ hpos = lprops->hpos;
+ if (!hpos)
+ return; /* Already top of the heap */
+ val1 = get_heap_comp_val(lprops, cat);
+ /* Compare to parent and, if greater, move up the heap */
+ do {
+ int ppos = (hpos - 1) / 2;
+
+ val2 = get_heap_comp_val(heap->arr[ppos], cat);
+ if (val2 >= val1)
+ return;
+ /* Greater than parent so move up */
+ heap->arr[ppos]->hpos = hpos;
+ heap->arr[hpos] = heap->arr[ppos];
+ heap->arr[ppos] = lprops;
+ lprops->hpos = ppos;
+ hpos = ppos;
+ } while (hpos);
+}
+
+/**
+ * adjust_lpt_heap - move a changed heap entry up or down the heap.
+ * @c: UBIFS file-system description object
+ * @heap: LEB category heap
+ * @lprops: LEB properties to move
+ * @hpos: heap position of @lprops
+ * @cat: LEB category
+ *
+ * Changed entries in a heap are moved up or down until the parent's value is
+ * greater. In the case of LPT's category heaps, the value is either the amount
+ * of free space or the amount of dirty space, depending on the category.
+ */
+static void adjust_lpt_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap,
+ struct ubifs_lprops *lprops, int hpos, int cat)
+{
+ int val1, val2, val3, cpos;
+
+ val1 = get_heap_comp_val(lprops, cat);
+ /* Compare to parent and, if greater than parent, move up the heap */
+ if (hpos) {
+ int ppos = (hpos - 1) / 2;
+
+ val2 = get_heap_comp_val(heap->arr[ppos], cat);
+ if (val1 > val2) {
+ /* Greater than parent so move up */
+ while (1) {
+ heap->arr[ppos]->hpos = hpos;
+ heap->arr[hpos] = heap->arr[ppos];
+ heap->arr[ppos] = lprops;
+ lprops->hpos = ppos;
+ hpos = ppos;
+ if (!hpos)
+ return;
+ ppos = (hpos - 1) / 2;
+ val2 = get_heap_comp_val(heap->arr[ppos], cat);
+ if (val1 <= val2)
+ return;
+ /* Still greater than parent so keep going */
+ }
+ }
+ }
+
+ /* Not greater than parent, so compare to children */
+ while (1) {
+ /* Compare to left child */
+ cpos = hpos * 2 + 1;
+ if (cpos >= heap->cnt)
+ return;
+ val2 = get_heap_comp_val(heap->arr[cpos], cat);
+ if (val1 < val2) {
+ /* Less than left child, so promote biggest child */
+ if (cpos + 1 < heap->cnt) {
+ val3 = get_heap_comp_val(heap->arr[cpos + 1],
+ cat);
+ if (val3 > val2)
+ cpos += 1; /* Right child is bigger */
+ }
+ heap->arr[cpos]->hpos = hpos;
+ heap->arr[hpos] = heap->arr[cpos];
+ heap->arr[cpos] = lprops;
+ lprops->hpos = cpos;
+ hpos = cpos;
+ continue;
+ }
+ /* Compare to right child */
+ cpos += 1;
+ if (cpos >= heap->cnt)
+ return;
+ val3 = get_heap_comp_val(heap->arr[cpos], cat);
+ if (val1 < val3) {
+ /* Less than right child, so promote right child */
+ heap->arr[cpos]->hpos = hpos;
+ heap->arr[hpos] = heap->arr[cpos];
+ heap->arr[cpos] = lprops;
+ lprops->hpos = cpos;
+ hpos = cpos;
+ continue;
+ }
+ return;
+ }
+}
+
+/**
+ * add_to_lpt_heap - add LEB properties to a LEB category heap.
+ * @c: UBIFS file-system description object
+ * @lprops: LEB properties to add
+ * @cat: LEB category
+ *
+ * This function returns %1 if @lprops is added to the heap for LEB category
+ * @cat, otherwise %0 is returned because the heap is full.
+ */
+static int add_to_lpt_heap(struct ubifs_info *c, struct ubifs_lprops *lprops,
+ int cat)
+{
+ struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1];
+
+ if (heap->cnt >= heap->max_cnt) {
+ const int b = LPT_HEAP_SZ / 2 - 1;
+ int cpos, val1, val2;
+
+ /* Compare to some other LEB on the bottom of heap */
+ /* Pick a position kind of randomly */
+ cpos = (((size_t)lprops >> 4) & b) + b;
+ ubifs_assert(cpos >= b);
+ ubifs_assert(cpos < LPT_HEAP_SZ);
+ ubifs_assert(cpos < heap->cnt);
+
+ val1 = get_heap_comp_val(lprops, cat);
+ val2 = get_heap_comp_val(heap->arr[cpos], cat);
+ if (val1 > val2) {
+ struct ubifs_lprops *lp;
+
+ lp = heap->arr[cpos];
+ lp->flags &= ~LPROPS_CAT_MASK;
+ lp->flags |= LPROPS_UNCAT;
+ list_add(&lp->list, &c->uncat_list);
+ lprops->hpos = cpos;
+ heap->arr[cpos] = lprops;
+ move_up_lpt_heap(c, heap, lprops, cat);
+ dbg_check_heap(c, heap, cat, lprops->hpos);
+ return 1; /* Added to heap */
+ }
+ dbg_check_heap(c, heap, cat, -1);
+ return 0; /* Not added to heap */
+ } else {
+ lprops->hpos = heap->cnt++;
+ heap->arr[lprops->hpos] = lprops;
+ move_up_lpt_heap(c, heap, lprops, cat);
+ dbg_check_heap(c, heap, cat, lprops->hpos);
+ return 1; /* Added to heap */
+ }
+}
+
+/**
+ * remove_from_lpt_heap - remove LEB properties from a LEB category heap.
+ * @c: UBIFS file-system description object
+ * @lprops: LEB properties to remove
+ * @cat: LEB category
+ */
+static void remove_from_lpt_heap(struct ubifs_info *c,
+ struct ubifs_lprops *lprops, int cat)
+{
+ struct ubifs_lpt_heap *heap;
+ int hpos = lprops->hpos;
+
+ heap = &c->lpt_heap[cat - 1];
+ ubifs_assert(hpos >= 0 && hpos < heap->cnt);
+ ubifs_assert(heap->arr[hpos] == lprops);
+ heap->cnt -= 1;
+ if (hpos < heap->cnt) {
+ heap->arr[hpos] = heap->arr[heap->cnt];
+ heap->arr[hpos]->hpos = hpos;
+ adjust_lpt_heap(c, heap, heap->arr[hpos], hpos, cat);
+ }
+ dbg_check_heap(c, heap, cat, -1);
+}
+
+/**
+ * lpt_heap_replace - replace lprops in a category heap.
+ * @c: UBIFS file-system description object
+ * @old_lprops: LEB properties to replace
+ * @new_lprops: LEB properties with which to replace
+ * @cat: LEB category
+ *
+ * During commit it is sometimes necessary to copy a pnode (see dirty_cow_pnode)
+ * and the lprops that the pnode contains. When that happens, references in
+ * the category heaps to those lprops must be updated to point to the new
+ * lprops. This function does that.
+ */
+static void lpt_heap_replace(struct ubifs_info *c,
+ struct ubifs_lprops *old_lprops,
+ struct ubifs_lprops *new_lprops, int cat)
+{
+ struct ubifs_lpt_heap *heap;
+ int hpos = new_lprops->hpos;
+
+ heap = &c->lpt_heap[cat - 1];
+ heap->arr[hpos] = new_lprops;
+}
+
+/**
+ * ubifs_add_to_cat - add LEB properties to a category list or heap.
+ * @c: UBIFS file-system description object
+ * @lprops: LEB properties to add
+ * @cat: LEB category to which to add
+ *
+ * LEB properties are categorized to enable fast find operations.
+ */
+void ubifs_add_to_cat(struct ubifs_info *c, struct ubifs_lprops *lprops,
+ int cat)
+{
+ switch (cat) {
+ case LPROPS_DIRTY:
+ case LPROPS_DIRTY_IDX:
+ case LPROPS_FREE:
+ if (add_to_lpt_heap(c, lprops, cat))
+ break;
+ /* No more room on heap so make it uncategorized */
+ cat = LPROPS_UNCAT;
+ /* Fall through */
+ case LPROPS_UNCAT:
+ list_add(&lprops->list, &c->uncat_list);
+ break;
+ case LPROPS_EMPTY:
+ list_add(&lprops->list, &c->empty_list);
+ break;
+ case LPROPS_FREEABLE:
+ list_add(&lprops->list, &c->freeable_list);
+ c->freeable_cnt += 1;
+ break;
+ case LPROPS_FRDI_IDX:
+ list_add(&lprops->list, &c->frdi_idx_list);
+ break;
+ default:
+ ubifs_assert(0);
+ }
+ lprops->flags &= ~LPROPS_CAT_MASK;
+ lprops->flags |= cat;
+}
+
+/**
+ * ubifs_remove_from_cat - remove LEB properties from a category list or heap.
+ * @c: UBIFS file-system description object
+ * @lprops: LEB properties to remove
+ * @cat: LEB category from which to remove
+ *
+ * LEB properties are categorized to enable fast find operations.
+ */
+static void ubifs_remove_from_cat(struct ubifs_info *c,
+ struct ubifs_lprops *lprops, int cat)
+{
+ switch (cat) {
+ case LPROPS_DIRTY:
+ case LPROPS_DIRTY_IDX:
+ case LPROPS_FREE:
+ remove_from_lpt_heap(c, lprops, cat);
+ break;
+ case LPROPS_FREEABLE:
+ c->freeable_cnt -= 1;
+ ubifs_assert(c->freeable_cnt >= 0);
+ /* Fall through */
+ case LPROPS_UNCAT:
+ case LPROPS_EMPTY:
+ case LPROPS_FRDI_IDX:
+ ubifs_assert(!list_empty(&lprops->list));
+ list_del(&lprops->list);
+ break;
+ default:
+ ubifs_assert(0);
+ }
+}
+
+/**
+ * ubifs_replace_cat - replace lprops in a category list or heap.
+ * @c: UBIFS file-system description object
+ * @old_lprops: LEB properties to replace
+ * @new_lprops: LEB properties with which to replace
+ *
+ * During commit it is sometimes necessary to copy a pnode (see dirty_cow_pnode)
+ * and the lprops that the pnode contains. When that happens, references in
+ * category lists and heaps must be replaced. This function does that.
+ */
+void ubifs_replace_cat(struct ubifs_info *c, struct ubifs_lprops *old_lprops,
+ struct ubifs_lprops *new_lprops)
+{
+ int cat;
+
+ cat = new_lprops->flags & LPROPS_CAT_MASK;
+ switch (cat) {
+ case LPROPS_DIRTY:
+ case LPROPS_DIRTY_IDX:
+ case LPROPS_FREE:
+ lpt_heap_replace(c, old_lprops, new_lprops, cat);
+ break;
+ case LPROPS_UNCAT:
+ case LPROPS_EMPTY:
+ case LPROPS_FREEABLE:
+ case LPROPS_FRDI_IDX:
+ list_replace(&old_lprops->list, &new_lprops->list);
+ break;
+ default:
+ ubifs_assert(0);
+ }
+}
+
+/**
+ * ubifs_ensure_cat - ensure LEB properties are categorized.
+ * @c: UBIFS file-system description object
+ * @lprops: LEB properties
+ *
+ * A LEB may have fallen off of the bottom of a heap, and ended up as
+ * uncategorized even though it has enough space for us now. If that is the case
+ * this function will put the LEB back onto a heap.
+ */
+void ubifs_ensure_cat(struct ubifs_info *c, struct ubifs_lprops *lprops)
+{
+ int cat = lprops->flags & LPROPS_CAT_MASK;
+
+ if (cat != LPROPS_UNCAT)
+ return;
+ cat = ubifs_categorize_lprops(c, lprops);
+ if (cat == LPROPS_UNCAT)
+ return;
+ ubifs_remove_from_cat(c, lprops, LPROPS_UNCAT);
+ ubifs_add_to_cat(c, lprops, cat);
+}
+
+/**
+ * ubifs_categorize_lprops - categorize LEB properties.
+ * @c: UBIFS file-system description object
+ * @lprops: LEB properties to categorize
+ *
+ * LEB properties are categorized to enable fast find operations. This function
+ * returns the LEB category to which the LEB properties belong. Note however
+ * that if the LEB category is stored as a heap and the heap is full, the
+ * LEB properties may have their category changed to %LPROPS_UNCAT.
+ */
+int ubifs_categorize_lprops(const struct ubifs_info *c,
+ const struct ubifs_lprops *lprops)
+{
+ if (lprops->flags & LPROPS_TAKEN)
+ return LPROPS_UNCAT;
+
+ if (lprops->free == c->leb_size) {
+ ubifs_assert(!(lprops->flags & LPROPS_INDEX));
+ return LPROPS_EMPTY;
+ }
+
+ if (lprops->free + lprops->dirty == c->leb_size) {
+ if (lprops->flags & LPROPS_INDEX)
+ return LPROPS_FRDI_IDX;
+ else
+ return LPROPS_FREEABLE;
+ }
+
+ if (lprops->flags & LPROPS_INDEX) {
+ if (lprops->dirty + lprops->free >= c->min_idx_node_sz)
+ return LPROPS_DIRTY_IDX;
+ } else {
+ if (lprops->dirty >= c->dead_wm &&
+ lprops->dirty > lprops->free)
+ return LPROPS_DIRTY;
+ if (lprops->free > 0)
+ return LPROPS_FREE;
+ }
+
+ return LPROPS_UNCAT;
+}
+
+/**
+ * change_category - change LEB properties category.
+ * @c: UBIFS file-system description object
+ * @lprops: LEB properties to recategorize
+ *
+ * LEB properties are categorized to enable fast find operations. When the LEB
+ * properties change they must be recategorized.
+ */
+static void change_category(struct ubifs_info *c, struct ubifs_lprops *lprops)
+{
+ int old_cat = lprops->flags & LPROPS_CAT_MASK;
+ int new_cat = ubifs_categorize_lprops(c, lprops);
+
+ if (old_cat == new_cat) {
+ struct ubifs_lpt_heap *heap = &c->lpt_heap[new_cat - 1];
+
+ /* lprops on a heap now must be moved up or down */
+ if (new_cat < 1 || new_cat > LPROPS_HEAP_CNT)
+ return; /* Not on a heap */
+ heap = &c->lpt_heap[new_cat - 1];
+ adjust_lpt_heap(c, heap, lprops, lprops->hpos, new_cat);
+ } else {
+ ubifs_remove_from_cat(c, lprops, old_cat);
+ ubifs_add_to_cat(c, lprops, new_cat);
+ }
+}
+
+/**
+ * calc_dark - calculate LEB dark space size.
+ * @c: the UBIFS file-system description object
+ * @spc: amount of free and dirty space in the LEB
+ *
+ * This function calculates amount of dark space in an LEB which has @spc bytes
+ * of free and dirty space. Returns the calculations result.
+ *
+ * Dark space is the space which is not always usable - it depends on which
+ * nodes are written in which order. E.g., if an LEB has only 512 free bytes,
+ * it is dark space, because it cannot fit a large data node. So UBIFS cannot
+ * count on this LEB and treat these 512 bytes as usable because it is not true
+ * if, for example, only big chunks of uncompressible data will be written to
+ * the FS.
+ */
+static int calc_dark(struct ubifs_info *c, int spc)
+{
+ ubifs_assert(!(spc & 7));
+
+ if (spc < c->dark_wm)
+ return spc;
+
+ /*
+ * If we have slightly more space then the dark space watermark, we can
+ * anyway safely assume it we'll be able to write a node of the
+ * smallest size there.
+ */
+ if (spc - c->dark_wm < MIN_WRITE_SZ)
+ return spc - MIN_WRITE_SZ;
+
+ return c->dark_wm;
+}
+
+/**
+ * is_lprops_dirty - determine if LEB properties are dirty.
+ * @c: the UBIFS file-system description object
+ * @lprops: LEB properties to test
+ */
+static int is_lprops_dirty(struct ubifs_info *c, struct ubifs_lprops *lprops)
+{
+ struct ubifs_pnode *pnode;
+ int pos;
+
+ pos = (lprops->lnum - c->main_first) & (UBIFS_LPT_FANOUT - 1);
+ pnode = (struct ubifs_pnode *)container_of(lprops - pos,
+ struct ubifs_pnode,
+ lprops[0]);
+ return !test_bit(COW_ZNODE, &pnode->flags) &&
+ test_bit(DIRTY_CNODE, &pnode->flags);
+}
+
+/**
+ * ubifs_change_lp - change LEB properties.
+ * @c: the UBIFS file-system description object
+ * @lp: LEB properties to change
+ * @free: new free space amount
+ * @dirty: new dirty space amount
+ * @flags: new flags
+ * @idx_gc_cnt: change to the count of idx_gc list
+ *
+ * This function changes LEB properties (@free, @dirty or @flag). However, the
+ * property which has the %LPROPS_NC value is not changed. Returns a pointer to
+ * the updated LEB properties on success and a negative error code on failure.
+ *
+ * Note, the LEB properties may have had to be copied (due to COW) and
+ * consequently the pointer returned may not be the same as the pointer
+ * passed.
+ */
+const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c,
+ const struct ubifs_lprops *lp,
+ int free, int dirty, int flags,
+ int idx_gc_cnt)
+{
+ /*
+ * This is the only function that is allowed to change lprops, so we
+ * discard the const qualifier.
+ */
+ struct ubifs_lprops *lprops = (struct ubifs_lprops *)lp;
+
+ dbg_lp("LEB %d, free %d, dirty %d, flags %d",
+ lprops->lnum, free, dirty, flags);
+
+ ubifs_assert(mutex_is_locked(&c->lp_mutex));
+ ubifs_assert(c->lst.empty_lebs >= 0 &&
+ c->lst.empty_lebs <= c->main_lebs);
+ ubifs_assert(c->freeable_cnt >= 0);
+ ubifs_assert(c->freeable_cnt <= c->main_lebs);
+ ubifs_assert(c->lst.taken_empty_lebs >= 0);
+ ubifs_assert(c->lst.taken_empty_lebs <= c->lst.empty_lebs);
+ ubifs_assert(!(c->lst.total_free & 7) && !(c->lst.total_dirty & 7));
+ ubifs_assert(!(c->lst.total_dead & 7) && !(c->lst.total_dark & 7));
+ ubifs_assert(!(c->lst.total_used & 7));
+ ubifs_assert(free == LPROPS_NC || free >= 0);
+ ubifs_assert(dirty == LPROPS_NC || dirty >= 0);
+
+ if (!is_lprops_dirty(c, lprops)) {
+ lprops = ubifs_lpt_lookup_dirty(c, lprops->lnum);
+ if (IS_ERR(lprops))
+ return lprops;
+ } else
+ ubifs_assert(lprops == ubifs_lpt_lookup_dirty(c, lprops->lnum));
+
+ ubifs_assert(!(lprops->free & 7) && !(lprops->dirty & 7));
+
+ spin_lock(&c->space_lock);
+ if ((lprops->flags & LPROPS_TAKEN) && lprops->free == c->leb_size)
+ c->lst.taken_empty_lebs -= 1;
+
+ if (!(lprops->flags & LPROPS_INDEX)) {
+ int old_spc;
+
+ old_spc = lprops->free + lprops->dirty;
+ if (old_spc < c->dead_wm)
+ c->lst.total_dead -= old_spc;
+ else
+ c->lst.total_dark -= calc_dark(c, old_spc);
+
+ c->lst.total_used -= c->leb_size - old_spc;
+ }
+
+ if (free != LPROPS_NC) {
+ free = ALIGN(free, 8);
+ c->lst.total_free += free - lprops->free;
+
+ /* Increase or decrease empty LEBs counter if needed */
+ if (free == c->leb_size) {
+ if (lprops->free != c->leb_size)
+ c->lst.empty_lebs += 1;
+ } else if (lprops->free == c->leb_size)
+ c->lst.empty_lebs -= 1;
+ lprops->free = free;
+ }
+
+ if (dirty != LPROPS_NC) {
+ dirty = ALIGN(dirty, 8);
+ c->lst.total_dirty += dirty - lprops->dirty;
+ lprops->dirty = dirty;
+ }
+
+ if (flags != LPROPS_NC) {
+ /* Take care about indexing LEBs counter if needed */
+ if ((lprops->flags & LPROPS_INDEX)) {
+ if (!(flags & LPROPS_INDEX))
+ c->lst.idx_lebs -= 1;
+ } else if (flags & LPROPS_INDEX)
+ c->lst.idx_lebs += 1;
+ lprops->flags = flags;
+ }
+
+ if (!(lprops->flags & LPROPS_INDEX)) {
+ int new_spc;
+
+ new_spc = lprops->free + lprops->dirty;
+ if (new_spc < c->dead_wm)
+ c->lst.total_dead += new_spc;
+ else
+ c->lst.total_dark += calc_dark(c, new_spc);
+
+ c->lst.total_used += c->leb_size - new_spc;
+ }
+
+ if ((lprops->flags & LPROPS_TAKEN) && lprops->free == c->leb_size)
+ c->lst.taken_empty_lebs += 1;
+
+ change_category(c, lprops);
+ c->idx_gc_cnt += idx_gc_cnt;
+ spin_unlock(&c->space_lock);
+ return lprops;
+}
+
+/**
+ * ubifs_get_lp_stats - get lprops statistics.
+ * @c: UBIFS file-system description object
+ * @st: return statistics
+ */
+void ubifs_get_lp_stats(struct ubifs_info *c, struct ubifs_lp_stats *lst)
+{
+ spin_lock(&c->space_lock);
+ memcpy(lst, &c->lst, sizeof(struct ubifs_lp_stats));
+ spin_unlock(&c->space_lock);
+}
+
+/**
+ * ubifs_change_one_lp - change LEB properties.
+ * @c: the UBIFS file-system description object
+ * @lnum: LEB to change properties for
+ * @free: amount of free space
+ * @dirty: amount of dirty space
+ * @flags_set: flags to set
+ * @flags_clean: flags to clean
+ * @idx_gc_cnt: change to the count of idx_gc list
+ *
+ * This function changes properties of LEB @lnum. It is a helper wrapper over
+ * 'ubifs_change_lp()' which hides lprops get/release. The arguments are the
+ * same as in case of 'ubifs_change_lp()'. Returns zero in case of success and
+ * a negative error code in case of failure.
+ */
+int ubifs_change_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
+ int flags_set, int flags_clean, int idx_gc_cnt)
+{
+ int err = 0, flags;
+ const struct ubifs_lprops *lp;
+
+ ubifs_get_lprops(c);
+
+ lp = ubifs_lpt_lookup_dirty(c, lnum);
+ if (IS_ERR(lp)) {
+ err = PTR_ERR(lp);
+ goto out;
+ }
+
+ flags = (lp->flags | flags_set) & ~flags_clean;
+ lp = ubifs_change_lp(c, lp, free, dirty, flags, idx_gc_cnt);
+ if (IS_ERR(lp))
+ err = PTR_ERR(lp);
+
+out:
+ ubifs_release_lprops(c);
+ return err;
+}
+
+/**
+ * ubifs_update_one_lp - update LEB properties.
+ * @c: the UBIFS file-system description object
+ * @lnum: LEB to change properties for
+ * @free: amount of free space
+ * @dirty: amount of dirty space to add
+ * @flags_set: flags to set
+ * @flags_clean: flags to clean
+ *
+ * This function is the same as 'ubifs_change_one_lp()' but @dirty is added to
+ * current dirty space, not substitutes it.
+ */
+int ubifs_update_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
+ int flags_set, int flags_clean)
+{
+ int err = 0, flags;
+ const struct ubifs_lprops *lp;
+
+ ubifs_get_lprops(c);
+
+ lp = ubifs_lpt_lookup_dirty(c, lnum);
+ if (IS_ERR(lp)) {
+ err = PTR_ERR(lp);
+ goto out;
+ }
+
+ flags = (lp->flags | flags_set) & ~flags_clean;
+ lp = ubifs_change_lp(c, lp, free, lp->dirty + dirty, flags, 0);
+ if (IS_ERR(lp))
+ err = PTR_ERR(lp);
+
+out:
+ ubifs_release_lprops(c);
+ return err;
+}
+
+/**
+ * ubifs_read_one_lp - read LEB properties.
+ * @c: the UBIFS file-system description object
+ * @lnum: LEB to read properties for
+ * @lp: where to store read properties
+ *
+ * This helper function reads properties of a LEB @lnum and stores them in @lp.
+ * Returns zero in case of success and a negative error code in case of
+ * failure.
+ */
+int ubifs_read_one_lp(struct ubifs_info *c, int lnum, struct ubifs_lprops *lp)
+{
+ int err = 0;
+ const struct ubifs_lprops *lpp;
+
+ ubifs_get_lprops(c);
+
+ lpp = ubifs_lpt_lookup(c, lnum);
+ if (IS_ERR(lpp)) {
+ err = PTR_ERR(lpp);
+ goto out;
+ }
+
+ memcpy(lp, lpp, sizeof(struct ubifs_lprops));
+
+out:
+ ubifs_release_lprops(c);
+ return err;
+}
+
+/**
+ * ubifs_fast_find_free - try to find a LEB with free space quickly.
+ * @c: the UBIFS file-system description object
+ *
+ * This function returns LEB properties for a LEB with free space or %NULL if
+ * the function is unable to find a LEB quickly.
+ */
+const struct ubifs_lprops *ubifs_fast_find_free(struct ubifs_info *c)
+{
+ struct ubifs_lprops *lprops;
+ struct ubifs_lpt_heap *heap;
+
+ ubifs_assert(mutex_is_locked(&c->lp_mutex));
+
+ heap = &c->lpt_heap[LPROPS_FREE - 1];
+ if (heap->cnt == 0)
+ return NULL;
+
+ lprops = heap->arr[0];
+ ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
+ ubifs_assert(!(lprops->flags & LPROPS_INDEX));
+ return lprops;
+}
+
+/**
+ * ubifs_fast_find_empty - try to find an empty LEB quickly.
+ * @c: the UBIFS file-system description object
+ *
+ * This function returns LEB properties for an empty LEB or %NULL if the
+ * function is unable to find an empty LEB quickly.
+ */
+const struct ubifs_lprops *ubifs_fast_find_empty(struct ubifs_info *c)
+{
+ struct ubifs_lprops *lprops;
+
+ ubifs_assert(mutex_is_locked(&c->lp_mutex));
+
+ if (list_empty(&c->empty_list))
+ return NULL;
+
+ lprops = list_entry(c->empty_list.next, struct ubifs_lprops, list);
+ ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
+ ubifs_assert(!(lprops->flags & LPROPS_INDEX));
+ ubifs_assert(lprops->free == c->leb_size);
+ return lprops;
+}
+
+/**
+ * ubifs_fast_find_freeable - try to find a freeable LEB quickly.
+ * @c: the UBIFS file-system description object
+ *
+ * This function returns LEB properties for a freeable LEB or %NULL if the
+ * function is unable to find a freeable LEB quickly.
+ */
+const struct ubifs_lprops *ubifs_fast_find_freeable(struct ubifs_info *c)
+{
+ struct ubifs_lprops *lprops;
+
+ ubifs_assert(mutex_is_locked(&c->lp_mutex));
+
+ if (list_empty(&c->freeable_list))
+ return NULL;
+
+ lprops = list_entry(c->freeable_list.next, struct ubifs_lprops, list);
+ ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
+ ubifs_assert(!(lprops->flags & LPROPS_INDEX));
+ ubifs_assert(lprops->free + lprops->dirty == c->leb_size);
+ ubifs_assert(c->freeable_cnt > 0);
+ return lprops;
+}
+
+/**
+ * ubifs_fast_find_frdi_idx - try to find a freeable index LEB quickly.
+ * @c: the UBIFS file-system description object
+ *
+ * This function returns LEB properties for a freeable index LEB or %NULL if the
+ * function is unable to find a freeable index LEB quickly.
+ */
+const struct ubifs_lprops *ubifs_fast_find_frdi_idx(struct ubifs_info *c)
+{
+ struct ubifs_lprops *lprops;
+
+ ubifs_assert(mutex_is_locked(&c->lp_mutex));
+
+ if (list_empty(&c->frdi_idx_list))
+ return NULL;
+
+ lprops = list_entry(c->frdi_idx_list.next, struct ubifs_lprops, list);
+ ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
+ ubifs_assert((lprops->flags & LPROPS_INDEX));
+ ubifs_assert(lprops->free + lprops->dirty == c->leb_size);
+ return lprops;
+}
diff --git a/fs/ubifs/lpt.c b/fs/ubifs/lpt.c
new file mode 100644
index 0000000..1a50d4c
--- /dev/null
+++ b/fs/ubifs/lpt.c
@@ -0,0 +1,1105 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ * Artem Bityutskiy (Битюцкий Ðртём)
+ */
+
+/*
+ * This file implements the LEB properties tree (LPT) area. The LPT area
+ * contains the LEB properties tree, a table of LPT area eraseblocks (ltab), and
+ * (for the "big" model) a table of saved LEB numbers (lsave). The LPT area sits
+ * between the log and the orphan area.
+ *
+ * The LPT area is like a miniature self-contained file system. It is required
+ * that it never runs out of space, is fast to access and update, and scales
+ * logarithmically. The LEB properties tree is implemented as a wandering tree
+ * much like the TNC, and the LPT area has its own garbage collection.
+ *
+ * The LPT has two slightly different forms called the "small model" and the
+ * "big model". The small model is used when the entire LEB properties table
+ * can be written into a single eraseblock. In that case, garbage collection
+ * consists of just writing the whole table, which therefore makes all other
+ * eraseblocks reusable. In the case of the big model, dirty eraseblocks are
+ * selected for garbage collection, which consists of marking the clean nodes in
+ * that LEB as dirty, and then only the dirty nodes are written out. Also, in
+ * the case of the big model, a table of LEB numbers is saved so that the entire
+ * LPT does not to be scanned looking for empty eraseblocks when UBIFS is first
+ * mounted.
+ */
+
+#include "ubifs.h"
+#include "crc16.h"
+#include <linux/math64.h>
+
+/**
+ * do_calc_lpt_geom - calculate sizes for the LPT area.
+ * @c: the UBIFS file-system description object
+ *
+ * Calculate the sizes of LPT bit fields, nodes, and tree, based on the
+ * properties of the flash and whether LPT is "big" (c->big_lpt).
+ */
+static void do_calc_lpt_geom(struct ubifs_info *c)
+{
+ int i, n, bits, per_leb_wastage, max_pnode_cnt;
+ long long sz, tot_wastage;
+
+ n = c->main_lebs + c->max_leb_cnt - c->leb_cnt;
+ max_pnode_cnt = DIV_ROUND_UP(n, UBIFS_LPT_FANOUT);
+
+ c->lpt_hght = 1;
+ n = UBIFS_LPT_FANOUT;
+ while (n < max_pnode_cnt) {
+ c->lpt_hght += 1;
+ n <<= UBIFS_LPT_FANOUT_SHIFT;
+ }
+
+ c->pnode_cnt = DIV_ROUND_UP(c->main_lebs, UBIFS_LPT_FANOUT);
+
+ n = DIV_ROUND_UP(c->pnode_cnt, UBIFS_LPT_FANOUT);
+ c->nnode_cnt = n;
+ for (i = 1; i < c->lpt_hght; i++) {
+ n = DIV_ROUND_UP(n, UBIFS_LPT_FANOUT);
+ c->nnode_cnt += n;
+ }
+
+ c->space_bits = fls(c->leb_size) - 3;
+ c->lpt_lnum_bits = fls(c->lpt_lebs);
+ c->lpt_offs_bits = fls(c->leb_size - 1);
+ c->lpt_spc_bits = fls(c->leb_size);
+
+ n = DIV_ROUND_UP(c->max_leb_cnt, UBIFS_LPT_FANOUT);
+ c->pcnt_bits = fls(n - 1);
+
+ c->lnum_bits = fls(c->max_leb_cnt - 1);
+
+ bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
+ (c->big_lpt ? c->pcnt_bits : 0) +
+ (c->space_bits * 2 + 1) * UBIFS_LPT_FANOUT;
+ c->pnode_sz = (bits + 7) / 8;
+
+ bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
+ (c->big_lpt ? c->pcnt_bits : 0) +
+ (c->lpt_lnum_bits + c->lpt_offs_bits) * UBIFS_LPT_FANOUT;
+ c->nnode_sz = (bits + 7) / 8;
+
+ bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
+ c->lpt_lebs * c->lpt_spc_bits * 2;
+ c->ltab_sz = (bits + 7) / 8;
+
+ bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
+ c->lnum_bits * c->lsave_cnt;
+ c->lsave_sz = (bits + 7) / 8;
+
+ /* Calculate the minimum LPT size */
+ c->lpt_sz = (long long)c->pnode_cnt * c->pnode_sz;
+ c->lpt_sz += (long long)c->nnode_cnt * c->nnode_sz;
+ c->lpt_sz += c->ltab_sz;
+ if (c->big_lpt)
+ c->lpt_sz += c->lsave_sz;
+
+ /* Add wastage */
+ sz = c->lpt_sz;
+ per_leb_wastage = max_t(int, c->pnode_sz, c->nnode_sz);
+ sz += per_leb_wastage;
+ tot_wastage = per_leb_wastage;
+ while (sz > c->leb_size) {
+ sz += per_leb_wastage;
+ sz -= c->leb_size;
+ tot_wastage += per_leb_wastage;
+ }
+ tot_wastage += ALIGN(sz, c->min_io_size) - sz;
+ c->lpt_sz += tot_wastage;
+}
+
+/**
+ * ubifs_calc_lpt_geom - calculate and check sizes for the LPT area.
+ * @c: the UBIFS file-system description object
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int ubifs_calc_lpt_geom(struct ubifs_info *c)
+{
+ int lebs_needed;
+ long long sz;
+
+ do_calc_lpt_geom(c);
+
+ /* Verify that lpt_lebs is big enough */
+ sz = c->lpt_sz * 2; /* Must have at least 2 times the size */
+ lebs_needed = div_u64(sz + c->leb_size - 1, c->leb_size);
+ if (lebs_needed > c->lpt_lebs) {
+ ubifs_err("too few LPT LEBs");
+ return -EINVAL;
+ }
+
+ /* Verify that ltab fits in a single LEB (since ltab is a single node */
+ if (c->ltab_sz > c->leb_size) {
+ ubifs_err("LPT ltab too big");
+ return -EINVAL;
+ }
+
+ c->check_lpt_free = c->big_lpt;
+ return 0;
+}
+
+/**
+ * ubifs_unpack_bits - unpack bit fields.
+ * @addr: address at which to unpack (passed and next address returned)
+ * @pos: bit position at which to unpack (passed and next position returned)
+ * @nrbits: number of bits of value to unpack (1-32)
+ *
+ * This functions returns the value unpacked.
+ */
+uint32_t ubifs_unpack_bits(uint8_t **addr, int *pos, int nrbits)
+{
+ const int k = 32 - nrbits;
+ uint8_t *p = *addr;
+ int b = *pos;
+ uint32_t uninitialized_var(val);
+ const int bytes = (nrbits + b + 7) >> 3;
+
+ ubifs_assert(nrbits > 0);
+ ubifs_assert(nrbits <= 32);
+ ubifs_assert(*pos >= 0);
+ ubifs_assert(*pos < 8);
+ if (b) {
+ switch (bytes) {
+ case 2:
+ val = p[1];
+ break;
+ case 3:
+ val = p[1] | ((uint32_t)p[2] << 8);
+ break;
+ case 4:
+ val = p[1] | ((uint32_t)p[2] << 8) |
+ ((uint32_t)p[3] << 16);
+ break;
+ case 5:
+ val = p[1] | ((uint32_t)p[2] << 8) |
+ ((uint32_t)p[3] << 16) |
+ ((uint32_t)p[4] << 24);
+ }
+ val <<= (8 - b);
+ val |= *p >> b;
+ nrbits += b;
+ } else {
+ switch (bytes) {
+ case 1:
+ val = p[0];
+ break;
+ case 2:
+ val = p[0] | ((uint32_t)p[1] << 8);
+ break;
+ case 3:
+ val = p[0] | ((uint32_t)p[1] << 8) |
+ ((uint32_t)p[2] << 16);
+ break;
+ case 4:
+ val = p[0] | ((uint32_t)p[1] << 8) |
+ ((uint32_t)p[2] << 16) |
+ ((uint32_t)p[3] << 24);
+ break;
+ }
+ }
+ val <<= k;
+ val >>= k;
+ b = nrbits & 7;
+ p += nrbits >> 3;
+ *addr = p;
+ *pos = b;
+ ubifs_assert((val >> nrbits) == 0 || nrbits - b == 32);
+ return val;
+}
+
+/**
+ * ubifs_add_lpt_dirt - add dirty space to LPT LEB properties.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number to which to add dirty space
+ * @dirty: amount of dirty space to add
+ */
+void ubifs_add_lpt_dirt(struct ubifs_info *c, int lnum, int dirty)
+{
+ if (!dirty || !lnum)
+ return;
+ dbg_lp("LEB %d add %d to %d",
+ lnum, dirty, c->ltab[lnum - c->lpt_first].dirty);
+ ubifs_assert(lnum >= c->lpt_first && lnum <= c->lpt_last);
+ c->ltab[lnum - c->lpt_first].dirty += dirty;
+}
+
+/**
+ * ubifs_add_nnode_dirt - add dirty space to LPT LEB properties.
+ * @c: UBIFS file-system description object
+ * @nnode: nnode for which to add dirt
+ */
+void ubifs_add_nnode_dirt(struct ubifs_info *c, struct ubifs_nnode *nnode)
+{
+ struct ubifs_nnode *np = nnode->parent;
+
+ if (np)
+ ubifs_add_lpt_dirt(c, np->nbranch[nnode->iip].lnum,
+ c->nnode_sz);
+ else {
+ ubifs_add_lpt_dirt(c, c->lpt_lnum, c->nnode_sz);
+ if (!(c->lpt_drty_flgs & LTAB_DIRTY)) {
+ c->lpt_drty_flgs |= LTAB_DIRTY;
+ ubifs_add_lpt_dirt(c, c->ltab_lnum, c->ltab_sz);
+ }
+ }
+}
+
+/**
+ * add_pnode_dirt - add dirty space to LPT LEB properties.
+ * @c: UBIFS file-system description object
+ * @pnode: pnode for which to add dirt
+ */
+static void add_pnode_dirt(struct ubifs_info *c, struct ubifs_pnode *pnode)
+{
+ ubifs_add_lpt_dirt(c, pnode->parent->nbranch[pnode->iip].lnum,
+ c->pnode_sz);
+}
+
+/**
+ * calc_nnode_num_from_parent - calculate nnode number.
+ * @c: UBIFS file-system description object
+ * @parent: parent nnode
+ * @iip: index in parent
+ *
+ * The nnode number is a number that uniquely identifies a nnode and can be used
+ * easily to traverse the tree from the root to that nnode.
+ *
+ * This function calculates and returns the nnode number based on the parent's
+ * nnode number and the index in parent.
+ */
+static int calc_nnode_num_from_parent(const struct ubifs_info *c,
+ struct ubifs_nnode *parent, int iip)
+{
+ int num, shft;
+
+ if (!parent)
+ return 1;
+ shft = (c->lpt_hght - parent->level) * UBIFS_LPT_FANOUT_SHIFT;
+ num = parent->num ^ (1 << shft);
+ num |= (UBIFS_LPT_FANOUT + iip) << shft;
+ return num;
+}
+
+/**
+ * calc_pnode_num_from_parent - calculate pnode number.
+ * @c: UBIFS file-system description object
+ * @parent: parent nnode
+ * @iip: index in parent
+ *
+ * The pnode number is a number that uniquely identifies a pnode and can be used
+ * easily to traverse the tree from the root to that pnode.
+ *
+ * This function calculates and returns the pnode number based on the parent's
+ * nnode number and the index in parent.
+ */
+static int calc_pnode_num_from_parent(const struct ubifs_info *c,
+ struct ubifs_nnode *parent, int iip)
+{
+ int i, n = c->lpt_hght - 1, pnum = parent->num, num = 0;
+
+ for (i = 0; i < n; i++) {
+ num <<= UBIFS_LPT_FANOUT_SHIFT;
+ num |= pnum & (UBIFS_LPT_FANOUT - 1);
+ pnum >>= UBIFS_LPT_FANOUT_SHIFT;
+ }
+ num <<= UBIFS_LPT_FANOUT_SHIFT;
+ num |= iip;
+ return num;
+}
+
+/**
+ * update_cats - add LEB properties of a pnode to LEB category lists and heaps.
+ * @c: UBIFS file-system description object
+ * @pnode: pnode
+ *
+ * When a pnode is loaded into memory, the LEB properties it contains are added,
+ * by this function, to the LEB category lists and heaps.
+ */
+static void update_cats(struct ubifs_info *c, struct ubifs_pnode *pnode)
+{
+ int i;
+
+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+ int cat = pnode->lprops[i].flags & LPROPS_CAT_MASK;
+ int lnum = pnode->lprops[i].lnum;
+
+ if (!lnum)
+ return;
+ ubifs_add_to_cat(c, &pnode->lprops[i], cat);
+ }
+}
+
+/**
+ * replace_cats - add LEB properties of a pnode to LEB category lists and heaps.
+ * @c: UBIFS file-system description object
+ * @old_pnode: pnode copied
+ * @new_pnode: pnode copy
+ *
+ * During commit it is sometimes necessary to copy a pnode
+ * (see dirty_cow_pnode). When that happens, references in
+ * category lists and heaps must be replaced. This function does that.
+ */
+static void replace_cats(struct ubifs_info *c, struct ubifs_pnode *old_pnode,
+ struct ubifs_pnode *new_pnode)
+{
+ int i;
+
+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+ if (!new_pnode->lprops[i].lnum)
+ return;
+ ubifs_replace_cat(c, &old_pnode->lprops[i],
+ &new_pnode->lprops[i]);
+ }
+}
+
+/**
+ * check_lpt_crc - check LPT node crc is correct.
+ * @c: UBIFS file-system description object
+ * @buf: buffer containing node
+ * @len: length of node
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int check_lpt_crc(void *buf, int len)
+{
+ int pos = 0;
+ uint8_t *addr = buf;
+ uint16_t crc, calc_crc;
+
+ crc = ubifs_unpack_bits(&addr, &pos, UBIFS_LPT_CRC_BITS);
+ calc_crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
+ len - UBIFS_LPT_CRC_BYTES);
+ if (crc != calc_crc) {
+ ubifs_err("invalid crc in LPT node: crc %hx calc %hx", crc,
+ calc_crc);
+ dbg_dump_stack();
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/**
+ * check_lpt_type - check LPT node type is correct.
+ * @c: UBIFS file-system description object
+ * @addr: address of type bit field is passed and returned updated here
+ * @pos: position of type bit field is passed and returned updated here
+ * @type: expected type
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int check_lpt_type(uint8_t **addr, int *pos, int type)
+{
+ int node_type;
+
+ node_type = ubifs_unpack_bits(addr, pos, UBIFS_LPT_TYPE_BITS);
+ if (node_type != type) {
+ ubifs_err("invalid type (%d) in LPT node type %d", node_type,
+ type);
+ dbg_dump_stack();
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/**
+ * unpack_pnode - unpack a pnode.
+ * @c: UBIFS file-system description object
+ * @buf: buffer containing packed pnode to unpack
+ * @pnode: pnode structure to fill
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int unpack_pnode(const struct ubifs_info *c, void *buf,
+ struct ubifs_pnode *pnode)
+{
+ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
+ int i, pos = 0, err;
+
+ err = check_lpt_type(&addr, &pos, UBIFS_LPT_PNODE);
+ if (err)
+ return err;
+ if (c->big_lpt)
+ pnode->num = ubifs_unpack_bits(&addr, &pos, c->pcnt_bits);
+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+ struct ubifs_lprops * const lprops = &pnode->lprops[i];
+
+ lprops->free = ubifs_unpack_bits(&addr, &pos, c->space_bits);
+ lprops->free <<= 3;
+ lprops->dirty = ubifs_unpack_bits(&addr, &pos, c->space_bits);
+ lprops->dirty <<= 3;
+
+ if (ubifs_unpack_bits(&addr, &pos, 1))
+ lprops->flags = LPROPS_INDEX;
+ else
+ lprops->flags = 0;
+ lprops->flags |= ubifs_categorize_lprops(c, lprops);
+ }
+ err = check_lpt_crc(buf, c->pnode_sz);
+ return err;
+}
+
+/**
+ * ubifs_unpack_nnode - unpack a nnode.
+ * @c: UBIFS file-system description object
+ * @buf: buffer containing packed nnode to unpack
+ * @nnode: nnode structure to fill
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int ubifs_unpack_nnode(const struct ubifs_info *c, void *buf,
+ struct ubifs_nnode *nnode)
+{
+ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
+ int i, pos = 0, err;
+
+ err = check_lpt_type(&addr, &pos, UBIFS_LPT_NNODE);
+ if (err)
+ return err;
+ if (c->big_lpt)
+ nnode->num = ubifs_unpack_bits(&addr, &pos, c->pcnt_bits);
+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+ int lnum;
+
+ lnum = ubifs_unpack_bits(&addr, &pos, c->lpt_lnum_bits) +
+ c->lpt_first;
+ if (lnum == c->lpt_last + 1)
+ lnum = 0;
+ nnode->nbranch[i].lnum = lnum;
+ nnode->nbranch[i].offs = ubifs_unpack_bits(&addr, &pos,
+ c->lpt_offs_bits);
+ }
+ err = check_lpt_crc(buf, c->nnode_sz);
+ return err;
+}
+
+/**
+ * unpack_ltab - unpack the LPT's own lprops table.
+ * @c: UBIFS file-system description object
+ * @buf: buffer from which to unpack
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int unpack_ltab(const struct ubifs_info *c, void *buf)
+{
+ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
+ int i, pos = 0, err;
+
+ err = check_lpt_type(&addr, &pos, UBIFS_LPT_LTAB);
+ if (err)
+ return err;
+ for (i = 0; i < c->lpt_lebs; i++) {
+ int free = ubifs_unpack_bits(&addr, &pos, c->lpt_spc_bits);
+ int dirty = ubifs_unpack_bits(&addr, &pos, c->lpt_spc_bits);
+
+ if (free < 0 || free > c->leb_size || dirty < 0 ||
+ dirty > c->leb_size || free + dirty > c->leb_size)
+ return -EINVAL;
+
+ c->ltab[i].free = free;
+ c->ltab[i].dirty = dirty;
+ c->ltab[i].tgc = 0;
+ c->ltab[i].cmt = 0;
+ }
+ err = check_lpt_crc(buf, c->ltab_sz);
+ return err;
+}
+
+/**
+ * validate_nnode - validate a nnode.
+ * @c: UBIFS file-system description object
+ * @nnode: nnode to validate
+ * @parent: parent nnode (or NULL for the root nnode)
+ * @iip: index in parent
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int validate_nnode(const struct ubifs_info *c, struct ubifs_nnode *nnode,
+ struct ubifs_nnode *parent, int iip)
+{
+ int i, lvl, max_offs;
+
+ if (c->big_lpt) {
+ int num = calc_nnode_num_from_parent(c, parent, iip);
+
+ if (nnode->num != num)
+ return -EINVAL;
+ }
+ lvl = parent ? parent->level - 1 : c->lpt_hght;
+ if (lvl < 1)
+ return -EINVAL;
+ if (lvl == 1)
+ max_offs = c->leb_size - c->pnode_sz;
+ else
+ max_offs = c->leb_size - c->nnode_sz;
+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+ int lnum = nnode->nbranch[i].lnum;
+ int offs = nnode->nbranch[i].offs;
+
+ if (lnum == 0) {
+ if (offs != 0)
+ return -EINVAL;
+ continue;
+ }
+ if (lnum < c->lpt_first || lnum > c->lpt_last)
+ return -EINVAL;
+ if (offs < 0 || offs > max_offs)
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/**
+ * validate_pnode - validate a pnode.
+ * @c: UBIFS file-system description object
+ * @pnode: pnode to validate
+ * @parent: parent nnode
+ * @iip: index in parent
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int validate_pnode(const struct ubifs_info *c, struct ubifs_pnode *pnode,
+ struct ubifs_nnode *parent, int iip)
+{
+ int i;
+
+ if (c->big_lpt) {
+ int num = calc_pnode_num_from_parent(c, parent, iip);
+
+ if (pnode->num != num)
+ return -EINVAL;
+ }
+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+ int free = pnode->lprops[i].free;
+ int dirty = pnode->lprops[i].dirty;
+
+ if (free < 0 || free > c->leb_size || free % c->min_io_size ||
+ (free & 7))
+ return -EINVAL;
+ if (dirty < 0 || dirty > c->leb_size || (dirty & 7))
+ return -EINVAL;
+ if (dirty + free > c->leb_size)
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/**
+ * set_pnode_lnum - set LEB numbers on a pnode.
+ * @c: UBIFS file-system description object
+ * @pnode: pnode to update
+ *
+ * This function calculates the LEB numbers for the LEB properties it contains
+ * based on the pnode number.
+ */
+static void set_pnode_lnum(const struct ubifs_info *c,
+ struct ubifs_pnode *pnode)
+{
+ int i, lnum;
+
+ lnum = (pnode->num << UBIFS_LPT_FANOUT_SHIFT) + c->main_first;
+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+ if (lnum >= c->leb_cnt)
+ return;
+ pnode->lprops[i].lnum = lnum++;
+ }
+}
+
+/**
+ * ubifs_read_nnode - read a nnode from flash and link it to the tree in memory.
+ * @c: UBIFS file-system description object
+ * @parent: parent nnode (or NULL for the root)
+ * @iip: index in parent
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
+{
+ struct ubifs_nbranch *branch = NULL;
+ struct ubifs_nnode *nnode = NULL;
+ void *buf = c->lpt_nod_buf;
+ int err, lnum, offs;
+
+ if (parent) {
+ branch = &parent->nbranch[iip];
+ lnum = branch->lnum;
+ offs = branch->offs;
+ } else {
+ lnum = c->lpt_lnum;
+ offs = c->lpt_offs;
+ }
+ nnode = kzalloc(sizeof(struct ubifs_nnode), GFP_NOFS);
+ if (!nnode) {
+ err = -ENOMEM;
+ goto out;
+ }
+ if (lnum == 0) {
+ /*
+ * This nnode was not written which just means that the LEB
+ * properties in the subtree below it describe empty LEBs. We
+ * make the nnode as though we had read it, which in fact means
+ * doing almost nothing.
+ */
+ if (c->big_lpt)
+ nnode->num = calc_nnode_num_from_parent(c, parent, iip);
+ } else {
+ err = ubi_read(c->ubi, lnum, buf, offs, c->nnode_sz);
+ if (err)
+ goto out;
+ err = ubifs_unpack_nnode(c, buf, nnode);
+ if (err)
+ goto out;
+ }
+ err = validate_nnode(c, nnode, parent, iip);
+ if (err)
+ goto out;
+ if (!c->big_lpt)
+ nnode->num = calc_nnode_num_from_parent(c, parent, iip);
+ if (parent) {
+ branch->nnode = nnode;
+ nnode->level = parent->level - 1;
+ } else {
+ c->nroot = nnode;
+ nnode->level = c->lpt_hght;
+ }
+ nnode->parent = parent;
+ nnode->iip = iip;
+ return 0;
+
+out:
+ ubifs_err("error %d reading nnode at %d:%d", err, lnum, offs);
+ kfree(nnode);
+ return err;
+}
+
+/**
+ * read_pnode - read a pnode from flash and link it to the tree in memory.
+ * @c: UBIFS file-system description object
+ * @parent: parent nnode
+ * @iip: index in parent
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
+{
+ struct ubifs_nbranch *branch;
+ struct ubifs_pnode *pnode = NULL;
+ void *buf = c->lpt_nod_buf;
+ int err, lnum, offs;
+
+ branch = &parent->nbranch[iip];
+ lnum = branch->lnum;
+ offs = branch->offs;
+ pnode = kzalloc(sizeof(struct ubifs_pnode), GFP_NOFS);
+ if (!pnode) {
+ err = -ENOMEM;
+ goto out;
+ }
+ if (lnum == 0) {
+ /*
+ * This pnode was not written which just means that the LEB
+ * properties in it describe empty LEBs. We make the pnode as
+ * though we had read it.
+ */
+ int i;
+
+ if (c->big_lpt)
+ pnode->num = calc_pnode_num_from_parent(c, parent, iip);
+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+ struct ubifs_lprops * const lprops = &pnode->lprops[i];
+
+ lprops->free = c->leb_size;
+ lprops->flags = ubifs_categorize_lprops(c, lprops);
+ }
+ } else {
+ err = ubi_read(c->ubi, lnum, buf, offs, c->pnode_sz);
+ if (err)
+ goto out;
+ err = unpack_pnode(c, buf, pnode);
+ if (err)
+ goto out;
+ }
+ err = validate_pnode(c, pnode, parent, iip);
+ if (err)
+ goto out;
+ if (!c->big_lpt)
+ pnode->num = calc_pnode_num_from_parent(c, parent, iip);
+ branch->pnode = pnode;
+ pnode->parent = parent;
+ pnode->iip = iip;
+ set_pnode_lnum(c, pnode);
+ c->pnodes_have += 1;
+ return 0;
+
+out:
+ ubifs_err("error %d reading pnode at %d:%d", err, lnum, offs);
+ dbg_dump_pnode(c, pnode, parent, iip);
+ dbg_msg("calc num: %d", calc_pnode_num_from_parent(c, parent, iip));
+ kfree(pnode);
+ return err;
+}
+
+/**
+ * read_ltab - read LPT's own lprops table.
+ * @c: UBIFS file-system description object
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int read_ltab(struct ubifs_info *c)
+{
+ int err;
+ void *buf;
+
+ buf = vmalloc(c->ltab_sz);
+ if (!buf)
+ return -ENOMEM;
+ err = ubi_read(c->ubi, c->ltab_lnum, buf, c->ltab_offs, c->ltab_sz);
+ if (err)
+ goto out;
+ err = unpack_ltab(c, buf);
+out:
+ vfree(buf);
+ return err;
+}
+
+/**
+ * ubifs_get_nnode - get a nnode.
+ * @c: UBIFS file-system description object
+ * @parent: parent nnode (or NULL for the root)
+ * @iip: index in parent
+ *
+ * This function returns a pointer to the nnode on success or a negative error
+ * code on failure.
+ */
+struct ubifs_nnode *ubifs_get_nnode(struct ubifs_info *c,
+ struct ubifs_nnode *parent, int iip)
+{
+ struct ubifs_nbranch *branch;
+ struct ubifs_nnode *nnode;
+ int err;
+
+ branch = &parent->nbranch[iip];
+ nnode = branch->nnode;
+ if (nnode)
+ return nnode;
+ err = ubifs_read_nnode(c, parent, iip);
+ if (err)
+ return ERR_PTR(err);
+ return branch->nnode;
+}
+
+/**
+ * ubifs_get_pnode - get a pnode.
+ * @c: UBIFS file-system description object
+ * @parent: parent nnode
+ * @iip: index in parent
+ *
+ * This function returns a pointer to the pnode on success or a negative error
+ * code on failure.
+ */
+struct ubifs_pnode *ubifs_get_pnode(struct ubifs_info *c,
+ struct ubifs_nnode *parent, int iip)
+{
+ struct ubifs_nbranch *branch;
+ struct ubifs_pnode *pnode;
+ int err;
+
+ branch = &parent->nbranch[iip];
+ pnode = branch->pnode;
+ if (pnode)
+ return pnode;
+ err = read_pnode(c, parent, iip);
+ if (err)
+ return ERR_PTR(err);
+ update_cats(c, branch->pnode);
+ return branch->pnode;
+}
+
+/**
+ * ubifs_lpt_lookup - lookup LEB properties in the LPT.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number to lookup
+ *
+ * This function returns a pointer to the LEB properties on success or a
+ * negative error code on failure.
+ */
+struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum)
+{
+ int err, i, h, iip, shft;
+ struct ubifs_nnode *nnode;
+ struct ubifs_pnode *pnode;
+
+ if (!c->nroot) {
+ err = ubifs_read_nnode(c, NULL, 0);
+ if (err)
+ return ERR_PTR(err);
+ }
+ nnode = c->nroot;
+ i = lnum - c->main_first;
+ shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
+ for (h = 1; h < c->lpt_hght; h++) {
+ iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
+ shft -= UBIFS_LPT_FANOUT_SHIFT;
+ nnode = ubifs_get_nnode(c, nnode, iip);
+ if (IS_ERR(nnode))
+ return ERR_PTR(PTR_ERR(nnode));
+ }
+ iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
+ shft -= UBIFS_LPT_FANOUT_SHIFT;
+ pnode = ubifs_get_pnode(c, nnode, iip);
+ if (IS_ERR(pnode))
+ return ERR_PTR(PTR_ERR(pnode));
+ iip = (i & (UBIFS_LPT_FANOUT - 1));
+ dbg_lp("LEB %d, free %d, dirty %d, flags %d", lnum,
+ pnode->lprops[iip].free, pnode->lprops[iip].dirty,
+ pnode->lprops[iip].flags);
+ return &pnode->lprops[iip];
+}
+
+/**
+ * dirty_cow_nnode - ensure a nnode is not being committed.
+ * @c: UBIFS file-system description object
+ * @nnode: nnode to check
+ *
+ * Returns dirtied nnode on success or negative error code on failure.
+ */
+static struct ubifs_nnode *dirty_cow_nnode(struct ubifs_info *c,
+ struct ubifs_nnode *nnode)
+{
+ struct ubifs_nnode *n;
+ int i;
+
+ if (!test_bit(COW_CNODE, &nnode->flags)) {
+ /* nnode is not being committed */
+ if (!test_and_set_bit(DIRTY_CNODE, &nnode->flags)) {
+ c->dirty_nn_cnt += 1;
+ ubifs_add_nnode_dirt(c, nnode);
+ }
+ return nnode;
+ }
+
+ /* nnode is being committed, so copy it */
+ n = kmalloc(sizeof(struct ubifs_nnode), GFP_NOFS);
+ if (unlikely(!n))
+ return ERR_PTR(-ENOMEM);
+
+ memcpy(n, nnode, sizeof(struct ubifs_nnode));
+ n->cnext = NULL;
+ __set_bit(DIRTY_CNODE, &n->flags);
+ __clear_bit(COW_CNODE, &n->flags);
+
+ /* The children now have new parent */
+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+ struct ubifs_nbranch *branch = &n->nbranch[i];
+
+ if (branch->cnode)
+ branch->cnode->parent = n;
+ }
+
+ ubifs_assert(!test_bit(OBSOLETE_CNODE, &nnode->flags));
+ __set_bit(OBSOLETE_CNODE, &nnode->flags);
+
+ c->dirty_nn_cnt += 1;
+ ubifs_add_nnode_dirt(c, nnode);
+ if (nnode->parent)
+ nnode->parent->nbranch[n->iip].nnode = n;
+ else
+ c->nroot = n;
+ return n;
+}
+
+/**
+ * dirty_cow_pnode - ensure a pnode is not being committed.
+ * @c: UBIFS file-system description object
+ * @pnode: pnode to check
+ *
+ * Returns dirtied pnode on success or negative error code on failure.
+ */
+static struct ubifs_pnode *dirty_cow_pnode(struct ubifs_info *c,
+ struct ubifs_pnode *pnode)
+{
+ struct ubifs_pnode *p;
+
+ if (!test_bit(COW_CNODE, &pnode->flags)) {
+ /* pnode is not being committed */
+ if (!test_and_set_bit(DIRTY_CNODE, &pnode->flags)) {
+ c->dirty_pn_cnt += 1;
+ add_pnode_dirt(c, pnode);
+ }
+ return pnode;
+ }
+
+ /* pnode is being committed, so copy it */
+ p = kmalloc(sizeof(struct ubifs_pnode), GFP_NOFS);
+ if (unlikely(!p))
+ return ERR_PTR(-ENOMEM);
+
+ memcpy(p, pnode, sizeof(struct ubifs_pnode));
+ p->cnext = NULL;
+ __set_bit(DIRTY_CNODE, &p->flags);
+ __clear_bit(COW_CNODE, &p->flags);
+ replace_cats(c, pnode, p);
+
+ ubifs_assert(!test_bit(OBSOLETE_CNODE, &pnode->flags));
+ __set_bit(OBSOLETE_CNODE, &pnode->flags);
+
+ c->dirty_pn_cnt += 1;
+ add_pnode_dirt(c, pnode);
+ pnode->parent->nbranch[p->iip].pnode = p;
+ return p;
+}
+
+/**
+ * ubifs_lpt_lookup_dirty - lookup LEB properties in the LPT.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number to lookup
+ *
+ * This function returns a pointer to the LEB properties on success or a
+ * negative error code on failure.
+ */
+struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum)
+{
+ int err, i, h, iip, shft;
+ struct ubifs_nnode *nnode;
+ struct ubifs_pnode *pnode;
+
+ if (!c->nroot) {
+ err = ubifs_read_nnode(c, NULL, 0);
+ if (err)
+ return ERR_PTR(err);
+ }
+ nnode = c->nroot;
+ nnode = dirty_cow_nnode(c, nnode);
+ if (IS_ERR(nnode))
+ return ERR_PTR(PTR_ERR(nnode));
+ i = lnum - c->main_first;
+ shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
+ for (h = 1; h < c->lpt_hght; h++) {
+ iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
+ shft -= UBIFS_LPT_FANOUT_SHIFT;
+ nnode = ubifs_get_nnode(c, nnode, iip);
+ if (IS_ERR(nnode))
+ return ERR_PTR(PTR_ERR(nnode));
+ nnode = dirty_cow_nnode(c, nnode);
+ if (IS_ERR(nnode))
+ return ERR_PTR(PTR_ERR(nnode));
+ }
+ iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
+ shft -= UBIFS_LPT_FANOUT_SHIFT;
+ pnode = ubifs_get_pnode(c, nnode, iip);
+ if (IS_ERR(pnode))
+ return ERR_PTR(PTR_ERR(pnode));
+ pnode = dirty_cow_pnode(c, pnode);
+ if (IS_ERR(pnode))
+ return ERR_PTR(PTR_ERR(pnode));
+ iip = (i & (UBIFS_LPT_FANOUT - 1));
+ dbg_lp("LEB %d, free %d, dirty %d, flags %d", lnum,
+ pnode->lprops[iip].free, pnode->lprops[iip].dirty,
+ pnode->lprops[iip].flags);
+ ubifs_assert(test_bit(DIRTY_CNODE, &pnode->flags));
+ return &pnode->lprops[iip];
+}
+
+/**
+ * lpt_init_rd - initialize the LPT for reading.
+ * @c: UBIFS file-system description object
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int lpt_init_rd(struct ubifs_info *c)
+{
+ int err, i;
+
+ c->ltab = vmalloc(sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs);
+ if (!c->ltab)
+ return -ENOMEM;
+
+ i = max_t(int, c->nnode_sz, c->pnode_sz);
+ c->lpt_nod_buf = kmalloc(i, GFP_KERNEL);
+ if (!c->lpt_nod_buf)
+ return -ENOMEM;
+
+ for (i = 0; i < LPROPS_HEAP_CNT; i++) {
+ c->lpt_heap[i].arr = kmalloc(sizeof(void *) * LPT_HEAP_SZ,
+ GFP_KERNEL);
+ if (!c->lpt_heap[i].arr)
+ return -ENOMEM;
+ c->lpt_heap[i].cnt = 0;
+ c->lpt_heap[i].max_cnt = LPT_HEAP_SZ;
+ }
+
+ c->dirty_idx.arr = kmalloc(sizeof(void *) * LPT_HEAP_SZ, GFP_KERNEL);
+ if (!c->dirty_idx.arr)
+ return -ENOMEM;
+ c->dirty_idx.cnt = 0;
+ c->dirty_idx.max_cnt = LPT_HEAP_SZ;
+
+ err = read_ltab(c);
+ if (err)
+ return err;
+
+ dbg_lp("space_bits %d", c->space_bits);
+ dbg_lp("lpt_lnum_bits %d", c->lpt_lnum_bits);
+ dbg_lp("lpt_offs_bits %d", c->lpt_offs_bits);
+ dbg_lp("lpt_spc_bits %d", c->lpt_spc_bits);
+ dbg_lp("pcnt_bits %d", c->pcnt_bits);
+ dbg_lp("lnum_bits %d", c->lnum_bits);
+ dbg_lp("pnode_sz %d", c->pnode_sz);
+ dbg_lp("nnode_sz %d", c->nnode_sz);
+ dbg_lp("ltab_sz %d", c->ltab_sz);
+ dbg_lp("lsave_sz %d", c->lsave_sz);
+ dbg_lp("lsave_cnt %d", c->lsave_cnt);
+ dbg_lp("lpt_hght %d", c->lpt_hght);
+ dbg_lp("big_lpt %d", c->big_lpt);
+ dbg_lp("LPT root is at %d:%d", c->lpt_lnum, c->lpt_offs);
+ dbg_lp("LPT head is at %d:%d", c->nhead_lnum, c->nhead_offs);
+ dbg_lp("LPT ltab is at %d:%d", c->ltab_lnum, c->ltab_offs);
+ if (c->big_lpt)
+ dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs);
+
+ return 0;
+}
+
+/**
+ * ubifs_lpt_init - initialize the LPT.
+ * @c: UBIFS file-system description object
+ * @rd: whether to initialize lpt for reading
+ * @wr: whether to initialize lpt for writing
+ *
+ * For mounting 'rw', @rd and @wr are both true. For mounting 'ro', @rd is true
+ * and @wr is false. For mounting from 'ro' to 'rw', @rd is false and @wr is
+ * true.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int ubifs_lpt_init(struct ubifs_info *c, int rd, int wr)
+{
+ int err;
+
+ if (rd) {
+ err = lpt_init_rd(c);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c
new file mode 100644
index 0000000..c0af818
--- /dev/null
+++ b/fs/ubifs/lpt_commit.c
@@ -0,0 +1,171 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ * Artem Bityutskiy (Битюцкий Ðртём)
+ */
+
+/*
+ * This file implements commit-related functionality of the LEB properties
+ * subsystem.
+ */
+
+#include "crc16.h"
+#include "ubifs.h"
+
+/**
+ * free_obsolete_cnodes - free obsolete cnodes for commit end.
+ * @c: UBIFS file-system description object
+ */
+static void free_obsolete_cnodes(struct ubifs_info *c)
+{
+ struct ubifs_cnode *cnode, *cnext;
+
+ cnext = c->lpt_cnext;
+ if (!cnext)
+ return;
+ do {
+ cnode = cnext;
+ cnext = cnode->cnext;
+ if (test_bit(OBSOLETE_CNODE, &cnode->flags))
+ kfree(cnode);
+ else
+ cnode->cnext = NULL;
+ } while (cnext != c->lpt_cnext);
+ c->lpt_cnext = NULL;
+}
+
+/**
+ * first_nnode - find the first nnode in memory.
+ * @c: UBIFS file-system description object
+ * @hght: height of tree where nnode found is returned here
+ *
+ * This function returns a pointer to the nnode found or %NULL if no nnode is
+ * found. This function is a helper to 'ubifs_lpt_free()'.
+ */
+static struct ubifs_nnode *first_nnode(struct ubifs_info *c, int *hght)
+{
+ struct ubifs_nnode *nnode;
+ int h, i, found;
+
+ nnode = c->nroot;
+ *hght = 0;
+ if (!nnode)
+ return NULL;
+ for (h = 1; h < c->lpt_hght; h++) {
+ found = 0;
+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+ if (nnode->nbranch[i].nnode) {
+ found = 1;
+ nnode = nnode->nbranch[i].nnode;
+ *hght = h;
+ break;
+ }
+ }
+ if (!found)
+ break;
+ }
+ return nnode;
+}
+
+/**
+ * next_nnode - find the next nnode in memory.
+ * @c: UBIFS file-system description object
+ * @nnode: nnode from which to start.
+ * @hght: height of tree where nnode is, is passed and returned here
+ *
+ * This function returns a pointer to the nnode found or %NULL if no nnode is
+ * found. This function is a helper to 'ubifs_lpt_free()'.
+ */
+static struct ubifs_nnode *next_nnode(struct ubifs_info *c,
+ struct ubifs_nnode *nnode, int *hght)
+{
+ struct ubifs_nnode *parent;
+ int iip, h, i, found;
+
+ parent = nnode->parent;
+ if (!parent)
+ return NULL;
+ if (nnode->iip == UBIFS_LPT_FANOUT - 1) {
+ *hght -= 1;
+ return parent;
+ }
+ for (iip = nnode->iip + 1; iip < UBIFS_LPT_FANOUT; iip++) {
+ nnode = parent->nbranch[iip].nnode;
+ if (nnode)
+ break;
+ }
+ if (!nnode) {
+ *hght -= 1;
+ return parent;
+ }
+ for (h = *hght + 1; h < c->lpt_hght; h++) {
+ found = 0;
+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+ if (nnode->nbranch[i].nnode) {
+ found = 1;
+ nnode = nnode->nbranch[i].nnode;
+ *hght = h;
+ break;
+ }
+ }
+ if (!found)
+ break;
+ }
+ return nnode;
+}
+
+/**
+ * ubifs_lpt_free - free resources owned by the LPT.
+ * @c: UBIFS file-system description object
+ * @wr_only: free only resources used for writing
+ */
+void ubifs_lpt_free(struct ubifs_info *c, int wr_only)
+{
+ struct ubifs_nnode *nnode;
+ int i, hght;
+
+ /* Free write-only things first */
+
+ free_obsolete_cnodes(c); /* Leftover from a failed commit */
+
+ vfree(c->ltab_cmt);
+ c->ltab_cmt = NULL;
+ vfree(c->lpt_buf);
+ c->lpt_buf = NULL;
+ kfree(c->lsave);
+ c->lsave = NULL;
+
+ if (wr_only)
+ return;
+
+ /* Now free the rest */
+
+ nnode = first_nnode(c, &hght);
+ while (nnode) {
+ for (i = 0; i < UBIFS_LPT_FANOUT; i++)
+ kfree(nnode->nbranch[i].nnode);
+ nnode = next_nnode(c, nnode, &hght);
+ }
+ for (i = 0; i < LPROPS_HEAP_CNT; i++)
+ kfree(c->lpt_heap[i].arr);
+ kfree(c->dirty_idx.arr);
+ kfree(c->nroot);
+ vfree(c->ltab);
+ kfree(c->lpt_nod_buf);
+}
diff --git a/fs/ubifs/master.c b/fs/ubifs/master.c
new file mode 100644
index 0000000..3f2926e
--- /dev/null
+++ b/fs/ubifs/master.c
@@ -0,0 +1,341 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Ðртём)
+ * Adrian Hunter
+ */
+
+/* This file implements reading and writing the master node */
+
+#include "ubifs.h"
+
+/**
+ * scan_for_master - search the valid master node.
+ * @c: UBIFS file-system description object
+ *
+ * This function scans the master node LEBs and search for the latest master
+ * node. Returns zero in case of success and a negative error code in case of
+ * failure.
+ */
+static int scan_for_master(struct ubifs_info *c)
+{
+ struct ubifs_scan_leb *sleb;
+ struct ubifs_scan_node *snod;
+ int lnum, offs = 0, nodes_cnt;
+
+ lnum = UBIFS_MST_LNUM;
+
+ sleb = ubifs_scan(c, lnum, 0, c->sbuf);
+ if (IS_ERR(sleb))
+ return PTR_ERR(sleb);
+ nodes_cnt = sleb->nodes_cnt;
+ if (nodes_cnt > 0) {
+ snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node,
+ list);
+ if (snod->type != UBIFS_MST_NODE)
+ goto out;
+ memcpy(c->mst_node, snod->node, snod->len);
+ offs = snod->offs;
+ }
+ ubifs_scan_destroy(sleb);
+
+ lnum += 1;
+
+ sleb = ubifs_scan(c, lnum, 0, c->sbuf);
+ if (IS_ERR(sleb))
+ return PTR_ERR(sleb);
+ if (sleb->nodes_cnt != nodes_cnt)
+ goto out;
+ if (!sleb->nodes_cnt)
+ goto out;
+ snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node, list);
+ if (snod->type != UBIFS_MST_NODE)
+ goto out;
+ if (snod->offs != offs)
+ goto out;
+ if (memcmp((void *)c->mst_node + UBIFS_CH_SZ,
+ (void *)snod->node + UBIFS_CH_SZ,
+ UBIFS_MST_NODE_SZ - UBIFS_CH_SZ))
+ goto out;
+ c->mst_offs = offs;
+ ubifs_scan_destroy(sleb);
+ return 0;
+
+out:
+ ubifs_scan_destroy(sleb);
+ return -EINVAL;
+}
+
+/**
+ * validate_master - validate master node.
+ * @c: UBIFS file-system description object
+ *
+ * This function validates data which was read from master node. Returns zero
+ * if the data is all right and %-EINVAL if not.
+ */
+static int validate_master(const struct ubifs_info *c)
+{
+ long long main_sz;
+ int err;
+
+ if (c->max_sqnum >= SQNUM_WATERMARK) {
+ err = 1;
+ goto out;
+ }
+
+ if (c->cmt_no >= c->max_sqnum) {
+ err = 2;
+ goto out;
+ }
+
+ if (c->highest_inum >= INUM_WATERMARK) {
+ err = 3;
+ goto out;
+ }
+
+ if (c->lhead_lnum < UBIFS_LOG_LNUM ||
+ c->lhead_lnum >= UBIFS_LOG_LNUM + c->log_lebs ||
+ c->lhead_offs < 0 || c->lhead_offs >= c->leb_size ||
+ c->lhead_offs & (c->min_io_size - 1)) {
+ err = 4;
+ goto out;
+ }
+
+ if (c->zroot.lnum >= c->leb_cnt || c->zroot.lnum < c->main_first ||
+ c->zroot.offs >= c->leb_size || c->zroot.offs & 7) {
+ err = 5;
+ goto out;
+ }
+
+ if (c->zroot.len < c->ranges[UBIFS_IDX_NODE].min_len ||
+ c->zroot.len > c->ranges[UBIFS_IDX_NODE].max_len) {
+ err = 6;
+ goto out;
+ }
+
+ if (c->gc_lnum >= c->leb_cnt || c->gc_lnum < c->main_first) {
+ err = 7;
+ goto out;
+ }
+
+ if (c->ihead_lnum >= c->leb_cnt || c->ihead_lnum < c->main_first ||
+ c->ihead_offs % c->min_io_size || c->ihead_offs < 0 ||
+ c->ihead_offs > c->leb_size || c->ihead_offs & 7) {
+ err = 8;
+ goto out;
+ }
+
+ main_sz = (long long)c->main_lebs * c->leb_size;
+ if (c->old_idx_sz & 7 || c->old_idx_sz >= main_sz) {
+ err = 9;
+ goto out;
+ }
+
+ if (c->lpt_lnum < c->lpt_first || c->lpt_lnum > c->lpt_last ||
+ c->lpt_offs < 0 || c->lpt_offs + c->nnode_sz > c->leb_size) {
+ err = 10;
+ goto out;
+ }
+
+ if (c->nhead_lnum < c->lpt_first || c->nhead_lnum > c->lpt_last ||
+ c->nhead_offs < 0 || c->nhead_offs % c->min_io_size ||
+ c->nhead_offs > c->leb_size) {
+ err = 11;
+ goto out;
+ }
+
+ if (c->ltab_lnum < c->lpt_first || c->ltab_lnum > c->lpt_last ||
+ c->ltab_offs < 0 ||
+ c->ltab_offs + c->ltab_sz > c->leb_size) {
+ err = 12;
+ goto out;
+ }
+
+ if (c->big_lpt && (c->lsave_lnum < c->lpt_first ||
+ c->lsave_lnum > c->lpt_last || c->lsave_offs < 0 ||
+ c->lsave_offs + c->lsave_sz > c->leb_size)) {
+ err = 13;
+ goto out;
+ }
+
+ if (c->lscan_lnum < c->main_first || c->lscan_lnum >= c->leb_cnt) {
+ err = 14;
+ goto out;
+ }
+
+ if (c->lst.empty_lebs < 0 || c->lst.empty_lebs > c->main_lebs - 2) {
+ err = 15;
+ goto out;
+ }
+
+ if (c->lst.idx_lebs < 0 || c->lst.idx_lebs > c->main_lebs - 1) {
+ err = 16;
+ goto out;
+ }
+
+ if (c->lst.total_free < 0 || c->lst.total_free > main_sz ||
+ c->lst.total_free & 7) {
+ err = 17;
+ goto out;
+ }
+
+ if (c->lst.total_dirty < 0 || (c->lst.total_dirty & 7)) {
+ err = 18;
+ goto out;
+ }
+
+ if (c->lst.total_used < 0 || (c->lst.total_used & 7)) {
+ err = 19;
+ goto out;
+ }
+
+ if (c->lst.total_free + c->lst.total_dirty +
+ c->lst.total_used > main_sz) {
+ err = 20;
+ goto out;
+ }
+
+ if (c->lst.total_dead + c->lst.total_dark +
+ c->lst.total_used + c->old_idx_sz > main_sz) {
+ err = 21;
+ goto out;
+ }
+
+ if (c->lst.total_dead < 0 ||
+ c->lst.total_dead > c->lst.total_free + c->lst.total_dirty ||
+ c->lst.total_dead & 7) {
+ err = 22;
+ goto out;
+ }
+
+ if (c->lst.total_dark < 0 ||
+ c->lst.total_dark > c->lst.total_free + c->lst.total_dirty ||
+ c->lst.total_dark & 7) {
+ err = 23;
+ goto out;
+ }
+
+ return 0;
+
+out:
+ ubifs_err("bad master node at offset %d error %d", c->mst_offs, err);
+ dbg_dump_node(c, c->mst_node);
+ return -EINVAL;
+}
+
+/**
+ * ubifs_read_master - read master node.
+ * @c: UBIFS file-system description object
+ *
+ * This function finds and reads the master node during file-system mount. If
+ * the flash is empty, it creates default master node as well. Returns zero in
+ * case of success and a negative error code in case of failure.
+ */
+int ubifs_read_master(struct ubifs_info *c)
+{
+ int err, old_leb_cnt;
+
+ c->mst_node = kzalloc(c->mst_node_alsz, GFP_KERNEL);
+ if (!c->mst_node)
+ return -ENOMEM;
+
+ err = scan_for_master(c);
+ if (err) {
+ err = ubifs_recover_master_node(c);
+ if (err)
+ /*
+ * Note, we do not free 'c->mst_node' here because the
+ * unmount routine will take care of this.
+ */
+ return err;
+ }
+
+ /* Make sure that the recovery flag is clear */
+ c->mst_node->flags &= cpu_to_le32(~UBIFS_MST_RCVRY);
+
+ c->max_sqnum = le64_to_cpu(c->mst_node->ch.sqnum);
+ c->highest_inum = le64_to_cpu(c->mst_node->highest_inum);
+ c->cmt_no = le64_to_cpu(c->mst_node->cmt_no);
+ c->zroot.lnum = le32_to_cpu(c->mst_node->root_lnum);
+ c->zroot.offs = le32_to_cpu(c->mst_node->root_offs);
+ c->zroot.len = le32_to_cpu(c->mst_node->root_len);
+ c->lhead_lnum = le32_to_cpu(c->mst_node->log_lnum);
+ c->gc_lnum = le32_to_cpu(c->mst_node->gc_lnum);
+ c->ihead_lnum = le32_to_cpu(c->mst_node->ihead_lnum);
+ c->ihead_offs = le32_to_cpu(c->mst_node->ihead_offs);
+ c->old_idx_sz = le64_to_cpu(c->mst_node->index_size);
+ c->lpt_lnum = le32_to_cpu(c->mst_node->lpt_lnum);
+ c->lpt_offs = le32_to_cpu(c->mst_node->lpt_offs);
+ c->nhead_lnum = le32_to_cpu(c->mst_node->nhead_lnum);
+ c->nhead_offs = le32_to_cpu(c->mst_node->nhead_offs);
+ c->ltab_lnum = le32_to_cpu(c->mst_node->ltab_lnum);
+ c->ltab_offs = le32_to_cpu(c->mst_node->ltab_offs);
+ c->lsave_lnum = le32_to_cpu(c->mst_node->lsave_lnum);
+ c->lsave_offs = le32_to_cpu(c->mst_node->lsave_offs);
+ c->lscan_lnum = le32_to_cpu(c->mst_node->lscan_lnum);
+ c->lst.empty_lebs = le32_to_cpu(c->mst_node->empty_lebs);
+ c->lst.idx_lebs = le32_to_cpu(c->mst_node->idx_lebs);
+ old_leb_cnt = le32_to_cpu(c->mst_node->leb_cnt);
+ c->lst.total_free = le64_to_cpu(c->mst_node->total_free);
+ c->lst.total_dirty = le64_to_cpu(c->mst_node->total_dirty);
+ c->lst.total_used = le64_to_cpu(c->mst_node->total_used);
+ c->lst.total_dead = le64_to_cpu(c->mst_node->total_dead);
+ c->lst.total_dark = le64_to_cpu(c->mst_node->total_dark);
+
+ c->calc_idx_sz = c->old_idx_sz;
+
+ if (c->mst_node->flags & cpu_to_le32(UBIFS_MST_NO_ORPHS))
+ c->no_orphs = 1;
+
+ if (old_leb_cnt != c->leb_cnt) {
+ /* The file system has been resized */
+ int growth = c->leb_cnt - old_leb_cnt;
+
+ if (c->leb_cnt < old_leb_cnt ||
+ c->leb_cnt < UBIFS_MIN_LEB_CNT) {
+ ubifs_err("bad leb_cnt on master node");
+ dbg_dump_node(c, c->mst_node);
+ return -EINVAL;
+ }
+
+ dbg_mnt("Auto resizing (master) from %d LEBs to %d LEBs",
+ old_leb_cnt, c->leb_cnt);
+ c->lst.empty_lebs += growth;
+ c->lst.total_free += growth * (long long)c->leb_size;
+ c->lst.total_dark += growth * (long long)c->dark_wm;
+
+ /*
+ * Reflect changes back onto the master node. N.B. the master
+ * node gets written immediately whenever mounting (or
+ * remounting) in read-write mode, so we do not need to write it
+ * here.
+ */
+ c->mst_node->leb_cnt = cpu_to_le32(c->leb_cnt);
+ c->mst_node->empty_lebs = cpu_to_le32(c->lst.empty_lebs);
+ c->mst_node->total_free = cpu_to_le64(c->lst.total_free);
+ c->mst_node->total_dark = cpu_to_le64(c->lst.total_dark);
+ }
+
+ err = validate_master(c);
+ if (err)
+ return err;
+
+ err = dbg_old_index_check_init(c, &c->zroot);
+
+ return err;
+}
diff --git a/fs/ubifs/misc.h b/fs/ubifs/misc.h
new file mode 100644
index 0000000..b745d86
--- /dev/null
+++ b/fs/ubifs/misc.h
@@ -0,0 +1,310 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Ðртём)
+ * Adrian Hunter
+ */
+
+/*
+ * This file contains miscellaneous helper functions.
+ */
+
+#ifndef __UBIFS_MISC_H__
+#define __UBIFS_MISC_H__
+
+/**
+ * ubifs_zn_dirty - check if znode is dirty.
+ * @znode: znode to check
+ *
+ * This helper function returns %1 if @znode is dirty and %0 otherwise.
+ */
+static inline int ubifs_zn_dirty(const struct ubifs_znode *znode)
+{
+ return !!test_bit(DIRTY_ZNODE, &znode->flags);
+}
+
+/**
+ * ubifs_wake_up_bgt - wake up background thread.
+ * @c: UBIFS file-system description object
+ */
+static inline void ubifs_wake_up_bgt(struct ubifs_info *c)
+{
+ if (c->bgt && !c->need_bgt) {
+ c->need_bgt = 1;
+ wake_up_process(c->bgt);
+ }
+}
+
+/**
+ * ubifs_tnc_find_child - find next child in znode.
+ * @znode: znode to search at
+ * @start: the zbranch index to start at
+ *
+ * This helper function looks for znode child starting at index @start. Returns
+ * the child or %NULL if no children were found.
+ */
+static inline struct ubifs_znode *
+ubifs_tnc_find_child(struct ubifs_znode *znode, int start)
+{
+ while (start < znode->child_cnt) {
+ if (znode->zbranch[start].znode)
+ return znode->zbranch[start].znode;
+ start += 1;
+ }
+
+ return NULL;
+}
+
+/**
+ * ubifs_inode - get UBIFS inode information by VFS 'struct inode' object.
+ * @inode: the VFS 'struct inode' pointer
+ */
+static inline struct ubifs_inode *ubifs_inode(const struct inode *inode)
+{
+ return container_of(inode, struct ubifs_inode, vfs_inode);
+}
+
+/**
+ * ubifs_compr_present - check if compressor was compiled in.
+ * @compr_type: compressor type to check
+ *
+ * This function returns %1 of compressor of type @compr_type is present, and
+ * %0 if not.
+ */
+static inline int ubifs_compr_present(int compr_type)
+{
+ ubifs_assert(compr_type >= 0 && compr_type < UBIFS_COMPR_TYPES_CNT);
+ return !!ubifs_compressors[compr_type]->capi_name;
+}
+
+/**
+ * ubifs_compr_name - get compressor name string by its type.
+ * @compr_type: compressor type
+ *
+ * This function returns compressor type string.
+ */
+static inline const char *ubifs_compr_name(int compr_type)
+{
+ ubifs_assert(compr_type >= 0 && compr_type < UBIFS_COMPR_TYPES_CNT);
+ return ubifs_compressors[compr_type]->name;
+}
+
+/**
+ * ubifs_wbuf_sync - synchronize write-buffer.
+ * @wbuf: write-buffer to synchronize
+ *
+ * This is the same as as 'ubifs_wbuf_sync_nolock()' but it does not assume
+ * that the write-buffer is already locked.
+ */
+static inline int ubifs_wbuf_sync(struct ubifs_wbuf *wbuf)
+{
+ int err;
+
+ mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
+ err = ubifs_wbuf_sync_nolock(wbuf);
+ mutex_unlock(&wbuf->io_mutex);
+ return err;
+}
+
+/**
+ * ubifs_leb_unmap - unmap an LEB.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number to unmap
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static inline int ubifs_leb_unmap(const struct ubifs_info *c, int lnum)
+{
+ int err;
+
+ if (c->ro_media)
+ return -EROFS;
+ err = ubi_leb_unmap(c->ubi, lnum);
+ if (err) {
+ ubifs_err("unmap LEB %d failed, error %d", lnum, err);
+ return err;
+ }
+
+ return 0;
+}
+
+/**
+ * ubifs_leb_write - write to a LEB.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number to write
+ * @buf: buffer to write from
+ * @offs: offset within LEB to write to
+ * @len: length to write
+ * @dtype: data type
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static inline int ubifs_leb_write(const struct ubifs_info *c, int lnum,
+ const void *buf, int offs, int len, int dtype)
+{
+ int err;
+
+ if (c->ro_media)
+ return -EROFS;
+ err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
+ if (err) {
+ ubifs_err("writing %d bytes at %d:%d, error %d",
+ len, lnum, offs, err);
+ return err;
+ }
+
+ return 0;
+}
+
+/**
+ * ubifs_leb_change - atomic LEB change.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number to write
+ * @buf: buffer to write from
+ * @len: length to write
+ * @dtype: data type
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static inline int ubifs_leb_change(const struct ubifs_info *c, int lnum,
+ const void *buf, int len, int dtype)
+{
+ int err;
+
+ if (c->ro_media)
+ return -EROFS;
+ err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
+ if (err) {
+ ubifs_err("changing %d bytes in LEB %d, error %d",
+ len, lnum, err);
+ return err;
+ }
+
+ return 0;
+}
+
+/**
+ * ubifs_add_dirt - add dirty space to LEB properties.
+ * @c: the UBIFS file-system description object
+ * @lnum: LEB to add dirty space for
+ * @dirty: dirty space to add
+ *
+ * This is a helper function which increased amount of dirty LEB space. Returns
+ * zero in case of success and a negative error code in case of failure.
+ */
+static inline int ubifs_add_dirt(struct ubifs_info *c, int lnum, int dirty)
+{
+ return ubifs_update_one_lp(c, lnum, LPROPS_NC, dirty, 0, 0);
+}
+
+/**
+ * ubifs_return_leb - return LEB to lprops.
+ * @c: the UBIFS file-system description object
+ * @lnum: LEB to return
+ *
+ * This helper function cleans the "taken" flag of a logical eraseblock in the
+ * lprops. Returns zero in case of success and a negative error code in case of
+ * failure.
+ */
+static inline int ubifs_return_leb(struct ubifs_info *c, int lnum)
+{
+ return ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0,
+ LPROPS_TAKEN, 0);
+}
+
+/**
+ * ubifs_idx_node_sz - return index node size.
+ * @c: the UBIFS file-system description object
+ * @child_cnt: number of children of this index node
+ */
+static inline int ubifs_idx_node_sz(const struct ubifs_info *c, int child_cnt)
+{
+ return UBIFS_IDX_NODE_SZ + (UBIFS_BRANCH_SZ + c->key_len) * child_cnt;
+}
+
+/**
+ * ubifs_idx_branch - return pointer to an index branch.
+ * @c: the UBIFS file-system description object
+ * @idx: index node
+ * @bnum: branch number
+ */
+static inline
+struct ubifs_branch *ubifs_idx_branch(const struct ubifs_info *c,
+ const struct ubifs_idx_node *idx,
+ int bnum)
+{
+ return (struct ubifs_branch *)((void *)idx->branches +
+ (UBIFS_BRANCH_SZ + c->key_len) * bnum);
+}
+
+/**
+ * ubifs_idx_key - return pointer to an index key.
+ * @c: the UBIFS file-system description object
+ * @idx: index node
+ */
+static inline void *ubifs_idx_key(const struct ubifs_info *c,
+ const struct ubifs_idx_node *idx)
+{
+ return (void *)((struct ubifs_branch *)idx->branches)->key;
+}
+
+/**
+ * ubifs_tnc_lookup - look up a file-system node.
+ * @c: UBIFS file-system description object
+ * @key: node key to lookup
+ * @node: the node is returned here
+ *
+ * This function look up and reads node with key @key. The caller has to make
+ * sure the @node buffer is large enough to fit the node. Returns zero in case
+ * of success, %-ENOENT if the node was not found, and a negative error code in
+ * case of failure.
+ */
+static inline int ubifs_tnc_lookup(struct ubifs_info *c,
+ const union ubifs_key *key, void *node)
+{
+ return ubifs_tnc_locate(c, key, node, NULL, NULL);
+}
+
+/**
+ * ubifs_get_lprops - get reference to LEB properties.
+ * @c: the UBIFS file-system description object
+ *
+ * This function locks lprops. Lprops have to be unlocked by
+ * 'ubifs_release_lprops()'.
+ */
+static inline void ubifs_get_lprops(struct ubifs_info *c)
+{
+ mutex_lock(&c->lp_mutex);
+}
+
+/**
+ * ubifs_release_lprops - release lprops lock.
+ * @c: the UBIFS file-system description object
+ *
+ * This function has to be called after each 'ubifs_get_lprops()' call to
+ * unlock lprops.
+ */
+static inline void ubifs_release_lprops(struct ubifs_info *c)
+{
+ ubifs_assert(mutex_is_locked(&c->lp_mutex));
+ ubifs_assert(c->lst.empty_lebs >= 0 &&
+ c->lst.empty_lebs <= c->main_lebs);
+ mutex_unlock(&c->lp_mutex);
+}
+
+#endif /* __UBIFS_MISC_H__ */
diff --git a/fs/ubifs/orphan.c b/fs/ubifs/orphan.c
new file mode 100644
index 0000000..d091031
--- /dev/null
+++ b/fs/ubifs/orphan.c
@@ -0,0 +1,316 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author: Adrian Hunter
+ */
+
+#include "ubifs.h"
+
+/*
+ * An orphan is an inode number whose inode node has been committed to the index
+ * with a link count of zero. That happens when an open file is deleted
+ * (unlinked) and then a commit is run. In the normal course of events the inode
+ * would be deleted when the file is closed. However in the case of an unclean
+ * unmount, orphans need to be accounted for. After an unclean unmount, the
+ * orphans' inodes must be deleted which means either scanning the entire index
+ * looking for them, or keeping a list on flash somewhere. This unit implements
+ * the latter approach.
+ *
+ * The orphan area is a fixed number of LEBs situated between the LPT area and
+ * the main area. The number of orphan area LEBs is specified when the file
+ * system is created. The minimum number is 1. The size of the orphan area
+ * should be so that it can hold the maximum number of orphans that are expected
+ * to ever exist at one time.
+ *
+ * The number of orphans that can fit in a LEB is:
+ *
+ * (c->leb_size - UBIFS_ORPH_NODE_SZ) / sizeof(__le64)
+ *
+ * For example: a 15872 byte LEB can fit 1980 orphans so 1 LEB may be enough.
+ *
+ * Orphans are accumulated in a rb-tree. When an inode's link count drops to
+ * zero, the inode number is added to the rb-tree. It is removed from the tree
+ * when the inode is deleted. Any new orphans that are in the orphan tree when
+ * the commit is run, are written to the orphan area in 1 or more orphan nodes.
+ * If the orphan area is full, it is consolidated to make space. There is
+ * always enough space because validation prevents the user from creating more
+ * than the maximum number of orphans allowed.
+ */
+
+/**
+ * tot_avail_orphs - calculate total space.
+ * @c: UBIFS file-system description object
+ *
+ * This function returns the number of orphans that can be written in half
+ * the total space. That leaves half the space for adding new orphans.
+ */
+static int tot_avail_orphs(struct ubifs_info *c)
+{
+ int avail_lebs, avail;
+
+ avail_lebs = c->orph_lebs;
+ avail = avail_lebs *
+ ((c->leb_size - UBIFS_ORPH_NODE_SZ) / sizeof(__le64));
+ return avail / 2;
+}
+
+/**
+ * ubifs_clear_orphans - erase all LEBs used for orphans.
+ * @c: UBIFS file-system description object
+ *
+ * If recovery is not required, then the orphans from the previous session
+ * are not needed. This function locates the LEBs used to record
+ * orphans, and un-maps them.
+ */
+int ubifs_clear_orphans(struct ubifs_info *c)
+{
+ int lnum, err;
+
+ for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) {
+ err = ubifs_leb_unmap(c, lnum);
+ if (err)
+ return err;
+ }
+ c->ohead_lnum = c->orph_first;
+ c->ohead_offs = 0;
+ return 0;
+}
+
+/**
+ * insert_dead_orphan - insert an orphan.
+ * @c: UBIFS file-system description object
+ * @inum: orphan inode number
+ *
+ * This function is a helper to the 'do_kill_orphans()' function. The orphan
+ * must be kept until the next commit, so it is added to the rb-tree and the
+ * deletion list.
+ */
+static int insert_dead_orphan(struct ubifs_info *c, ino_t inum)
+{
+ struct ubifs_orphan *orphan, *o;
+ struct rb_node **p, *parent = NULL;
+
+ orphan = kzalloc(sizeof(struct ubifs_orphan), GFP_KERNEL);
+ if (!orphan)
+ return -ENOMEM;
+ orphan->inum = inum;
+
+ p = &c->orph_tree.rb_node;
+ while (*p) {
+ parent = *p;
+ o = rb_entry(parent, struct ubifs_orphan, rb);
+ if (inum < o->inum)
+ p = &(*p)->rb_left;
+ else if (inum > o->inum)
+ p = &(*p)->rb_right;
+ else {
+ /* Already added - no problem */
+ kfree(orphan);
+ return 0;
+ }
+ }
+ c->tot_orphans += 1;
+ rb_link_node(&orphan->rb, parent, p);
+ rb_insert_color(&orphan->rb, &c->orph_tree);
+ list_add_tail(&orphan->list, &c->orph_list);
+ orphan->dnext = c->orph_dnext;
+ c->orph_dnext = orphan;
+ dbg_mnt("ino %lu, new %d, tot %d", (unsigned long)inum,
+ c->new_orphans, c->tot_orphans);
+ return 0;
+}
+
+/**
+ * do_kill_orphans - remove orphan inodes from the index.
+ * @c: UBIFS file-system description object
+ * @sleb: scanned LEB
+ * @last_cmt_no: cmt_no of last orphan node read is passed and returned here
+ * @outofdate: whether the LEB is out of date is returned here
+ * @last_flagged: whether the end orphan node is encountered
+ *
+ * This function is a helper to the 'kill_orphans()' function. It goes through
+ * every orphan node in a LEB and for every inode number recorded, removes
+ * all keys for that inode from the TNC.
+ */
+static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
+ unsigned long long *last_cmt_no, int *outofdate,
+ int *last_flagged)
+{
+ struct ubifs_scan_node *snod;
+ struct ubifs_orph_node *orph;
+ unsigned long long cmt_no;
+ ino_t inum;
+ int i, n, err, first = 1;
+
+ list_for_each_entry(snod, &sleb->nodes, list) {
+ if (snod->type != UBIFS_ORPH_NODE) {
+ ubifs_err("invalid node type %d in orphan area at "
+ "%d:%d", snod->type, sleb->lnum, snod->offs);
+ dbg_dump_node(c, snod->node);
+ return -EINVAL;
+ }
+
+ orph = snod->node;
+
+ /* Check commit number */
+ cmt_no = le64_to_cpu(orph->cmt_no) & LLONG_MAX;
+ /*
+ * The commit number on the master node may be less, because
+ * of a failed commit. If there are several failed commits in a
+ * row, the commit number written on orphan nodes will continue
+ * to increase (because the commit number is adjusted here) even
+ * though the commit number on the master node stays the same
+ * because the master node has not been re-written.
+ */
+ if (cmt_no > c->cmt_no)
+ c->cmt_no = cmt_no;
+ if (cmt_no < *last_cmt_no && *last_flagged) {
+ /*
+ * The last orphan node had a higher commit number and
+ * was flagged as the last written for that commit
+ * number. That makes this orphan node, out of date.
+ */
+ if (!first) {
+ ubifs_err("out of order commit number %llu in "
+ "orphan node at %d:%d",
+ cmt_no, sleb->lnum, snod->offs);
+ dbg_dump_node(c, snod->node);
+ return -EINVAL;
+ }
+ dbg_rcvry("out of date LEB %d", sleb->lnum);
+ *outofdate = 1;
+ return 0;
+ }
+
+ if (first)
+ first = 0;
+
+ n = (le32_to_cpu(orph->ch.len) - UBIFS_ORPH_NODE_SZ) >> 3;
+ for (i = 0; i < n; i++) {
+ inum = le64_to_cpu(orph->inos[i]);
+ dbg_rcvry("deleting orphaned inode %lu",
+ (unsigned long)inum);
+ err = ubifs_tnc_remove_ino(c, inum);
+ if (err)
+ return err;
+ err = insert_dead_orphan(c, inum);
+ if (err)
+ return err;
+ }
+
+ *last_cmt_no = cmt_no;
+ if (le64_to_cpu(orph->cmt_no) & (1ULL << 63)) {
+ dbg_rcvry("last orph node for commit %llu at %d:%d",
+ cmt_no, sleb->lnum, snod->offs);
+ *last_flagged = 1;
+ } else
+ *last_flagged = 0;
+ }
+
+ return 0;
+}
+
+/**
+ * kill_orphans - remove all orphan inodes from the index.
+ * @c: UBIFS file-system description object
+ *
+ * If recovery is required, then orphan inodes recorded during the previous
+ * session (which ended with an unclean unmount) must be deleted from the index.
+ * This is done by updating the TNC, but since the index is not updated until
+ * the next commit, the LEBs where the orphan information is recorded are not
+ * erased until the next commit.
+ */
+static int kill_orphans(struct ubifs_info *c)
+{
+ unsigned long long last_cmt_no = 0;
+ int lnum, err = 0, outofdate = 0, last_flagged = 0;
+
+ c->ohead_lnum = c->orph_first;
+ c->ohead_offs = 0;
+ /* Check no-orphans flag and skip this if no orphans */
+ if (c->no_orphs) {
+ dbg_rcvry("no orphans");
+ return 0;
+ }
+ /*
+ * Orph nodes always start at c->orph_first and are written to each
+ * successive LEB in turn. Generally unused LEBs will have been unmapped
+ * but may contain out of date orphan nodes if the unmap didn't go
+ * through. In addition, the last orphan node written for each commit is
+ * marked (top bit of orph->cmt_no is set to 1). It is possible that
+ * there are orphan nodes from the next commit (i.e. the commit did not
+ * complete successfully). In that case, no orphans will have been lost
+ * due to the way that orphans are written, and any orphans added will
+ * be valid orphans anyway and so can be deleted.
+ */
+ for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) {
+ struct ubifs_scan_leb *sleb;
+
+ dbg_rcvry("LEB %d", lnum);
+ sleb = ubifs_scan(c, lnum, 0, c->sbuf);
+ if (IS_ERR(sleb)) {
+ sleb = ubifs_recover_leb(c, lnum, 0, c->sbuf, 0);
+ if (IS_ERR(sleb)) {
+ err = PTR_ERR(sleb);
+ break;
+ }
+ }
+ err = do_kill_orphans(c, sleb, &last_cmt_no, &outofdate,
+ &last_flagged);
+ if (err || outofdate) {
+ ubifs_scan_destroy(sleb);
+ break;
+ }
+ if (sleb->endpt) {
+ c->ohead_lnum = lnum;
+ c->ohead_offs = sleb->endpt;
+ }
+ ubifs_scan_destroy(sleb);
+ }
+ return err;
+}
+
+/**
+ * ubifs_mount_orphans - delete orphan inodes and erase LEBs that recorded them.
+ * @c: UBIFS file-system description object
+ * @unclean: indicates recovery from unclean unmount
+ * @read_only: indicates read only mount
+ *
+ * This function is called when mounting to erase orphans from the previous
+ * session. If UBIFS was not unmounted cleanly, then the inodes recorded as
+ * orphans are deleted.
+ */
+int ubifs_mount_orphans(struct ubifs_info *c, int unclean, int read_only)
+{
+ int err = 0;
+
+ c->max_orphans = tot_avail_orphs(c);
+
+ if (!read_only) {
+ c->orph_buf = vmalloc(c->leb_size);
+ if (!c->orph_buf)
+ return -ENOMEM;
+ }
+
+ if (unclean)
+ err = kill_orphans(c);
+ else if (!read_only)
+ err = ubifs_clear_orphans(c);
+
+ return err;
+}
diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
new file mode 100644
index 0000000..fe3b364
--- /dev/null
+++ b/fs/ubifs/recovery.c
@@ -0,0 +1,1249 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ * Artem Bityutskiy (Битюцкий Ðртём)
+ */
+
+/*
+ * This file implements functions needed to recover from unclean un-mounts.
+ * When UBIFS is mounted, it checks a flag on the master node to determine if
+ * an un-mount was completed sucessfully. If not, the process of mounting
+ * incorparates additional checking and fixing of on-flash data structures.
+ * UBIFS always cleans away all remnants of an unclean un-mount, so that
+ * errors do not accumulate. However UBIFS defers recovery if it is mounted
+ * read-only, and the flash is not modified in that case.
+ */
+
+#include "ubifs.h"
+
+/**
+ * is_empty - determine whether a buffer is empty (contains all 0xff).
+ * @buf: buffer to clean
+ * @len: length of buffer
+ *
+ * This function returns %1 if the buffer is empty (contains all 0xff) otherwise
+ * %0 is returned.
+ */
+static int is_empty(void *buf, int len)
+{
+ uint8_t *p = buf;
+ int i;
+
+ for (i = 0; i < len; i++)
+ if (*p++ != 0xff)
+ return 0;
+ return 1;
+}
+
+/**
+ * get_master_node - get the last valid master node allowing for corruption.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number
+ * @pbuf: buffer containing the LEB read, is returned here
+ * @mst: master node, if found, is returned here
+ * @cor: corruption, if found, is returned here
+ *
+ * This function allocates a buffer, reads the LEB into it, and finds and
+ * returns the last valid master node allowing for one area of corruption.
+ * The corrupt area, if there is one, must be consistent with the assumption
+ * that it is the result of an unclean unmount while the master node was being
+ * written. Under those circumstances, it is valid to use the previously written
+ * master node.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int get_master_node(const struct ubifs_info *c, int lnum, void **pbuf,
+ struct ubifs_mst_node **mst, void **cor)
+{
+ const int sz = c->mst_node_alsz;
+ int err, offs, len;
+ void *sbuf, *buf;
+
+ sbuf = vmalloc(c->leb_size);
+ if (!sbuf)
+ return -ENOMEM;
+
+ err = ubi_read(c->ubi, lnum, sbuf, 0, c->leb_size);
+ if (err && err != -EBADMSG)
+ goto out_free;
+
+ /* Find the first position that is definitely not a node */
+ offs = 0;
+ buf = sbuf;
+ len = c->leb_size;
+ while (offs + UBIFS_MST_NODE_SZ <= c->leb_size) {
+ struct ubifs_ch *ch = buf;
+
+ if (le32_to_cpu(ch->magic) != UBIFS_NODE_MAGIC)
+ break;
+ offs += sz;
+ buf += sz;
+ len -= sz;
+ }
+ /* See if there was a valid master node before that */
+ if (offs) {
+ int ret;
+
+ offs -= sz;
+ buf -= sz;
+ len += sz;
+ ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 1);
+ if (ret != SCANNED_A_NODE && offs) {
+ /* Could have been corruption so check one place back */
+ offs -= sz;
+ buf -= sz;
+ len += sz;
+ ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 1);
+ if (ret != SCANNED_A_NODE)
+ /*
+ * We accept only one area of corruption because
+ * we are assuming that it was caused while
+ * trying to write a master node.
+ */
+ goto out_err;
+ }
+ if (ret == SCANNED_A_NODE) {
+ struct ubifs_ch *ch = buf;
+
+ if (ch->node_type != UBIFS_MST_NODE)
+ goto out_err;
+ dbg_rcvry("found a master node at %d:%d", lnum, offs);
+ *mst = buf;
+ offs += sz;
+ buf += sz;
+ len -= sz;
+ }
+ }
+ /* Check for corruption */
+ if (offs < c->leb_size) {
+ if (!is_empty(buf, min_t(int, len, sz))) {
+ *cor = buf;
+ dbg_rcvry("found corruption at %d:%d", lnum, offs);
+ }
+ offs += sz;
+ buf += sz;
+ len -= sz;
+ }
+ /* Check remaining empty space */
+ if (offs < c->leb_size)
+ if (!is_empty(buf, len))
+ goto out_err;
+ *pbuf = sbuf;
+ return 0;
+
+out_err:
+ err = -EINVAL;
+out_free:
+ vfree(sbuf);
+ *mst = NULL;
+ *cor = NULL;
+ return err;
+}
+
+/**
+ * write_rcvrd_mst_node - write recovered master node.
+ * @c: UBIFS file-system description object
+ * @mst: master node
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int write_rcvrd_mst_node(struct ubifs_info *c,
+ struct ubifs_mst_node *mst)
+{
+ int err = 0, lnum = UBIFS_MST_LNUM, sz = c->mst_node_alsz;
+ __le32 save_flags;
+
+ dbg_rcvry("recovery");
+
+ save_flags = mst->flags;
+ mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY);
+
+ ubifs_prepare_node(c, mst, UBIFS_MST_NODE_SZ, 1);
+ err = ubi_leb_change(c->ubi, lnum, mst, sz, UBI_SHORTTERM);
+ if (err)
+ goto out;
+ err = ubi_leb_change(c->ubi, lnum + 1, mst, sz, UBI_SHORTTERM);
+ if (err)
+ goto out;
+out:
+ mst->flags = save_flags;
+ return err;
+}
+
+/**
+ * ubifs_recover_master_node - recover the master node.
+ * @c: UBIFS file-system description object
+ *
+ * This function recovers the master node from corruption that may occur due to
+ * an unclean unmount.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int ubifs_recover_master_node(struct ubifs_info *c)
+{
+ void *buf1 = NULL, *buf2 = NULL, *cor1 = NULL, *cor2 = NULL;
+ struct ubifs_mst_node *mst1 = NULL, *mst2 = NULL, *mst;
+ const int sz = c->mst_node_alsz;
+ int err, offs1, offs2;
+
+ dbg_rcvry("recovery");
+
+ err = get_master_node(c, UBIFS_MST_LNUM, &buf1, &mst1, &cor1);
+ if (err)
+ goto out_free;
+
+ err = get_master_node(c, UBIFS_MST_LNUM + 1, &buf2, &mst2, &cor2);
+ if (err)
+ goto out_free;
+
+ if (mst1) {
+ offs1 = (void *)mst1 - buf1;
+ if ((le32_to_cpu(mst1->flags) & UBIFS_MST_RCVRY) &&
+ (offs1 == 0 && !cor1)) {
+ /*
+ * mst1 was written by recovery at offset 0 with no
+ * corruption.
+ */
+ dbg_rcvry("recovery recovery");
+ mst = mst1;
+ } else if (mst2) {
+ offs2 = (void *)mst2 - buf2;
+ if (offs1 == offs2) {
+ /* Same offset, so must be the same */
+ if (memcmp((void *)mst1 + UBIFS_CH_SZ,
+ (void *)mst2 + UBIFS_CH_SZ,
+ UBIFS_MST_NODE_SZ - UBIFS_CH_SZ))
+ goto out_err;
+ mst = mst1;
+ } else if (offs2 + sz == offs1) {
+ /* 1st LEB was written, 2nd was not */
+ if (cor1)
+ goto out_err;
+ mst = mst1;
+ } else if (offs1 == 0 && offs2 + sz >= c->leb_size) {
+ /* 1st LEB was unmapped and written, 2nd not */
+ if (cor1)
+ goto out_err;
+ mst = mst1;
+ } else
+ goto out_err;
+ } else {
+ /*
+ * 2nd LEB was unmapped and about to be written, so
+ * there must be only one master node in the first LEB
+ * and no corruption.
+ */
+ if (offs1 != 0 || cor1)
+ goto out_err;
+ mst = mst1;
+ }
+ } else {
+ if (!mst2)
+ goto out_err;
+ /*
+ * 1st LEB was unmapped and about to be written, so there must
+ * be no room left in 2nd LEB.
+ */
+ offs2 = (void *)mst2 - buf2;
+ if (offs2 + sz + sz <= c->leb_size)
+ goto out_err;
+ mst = mst2;
+ }
+
+ dbg_rcvry("recovered master node from LEB %d",
+ (mst == mst1 ? UBIFS_MST_LNUM : UBIFS_MST_LNUM + 1));
+
+ memcpy(c->mst_node, mst, UBIFS_MST_NODE_SZ);
+
+ if ((c->vfs_sb->s_flags & MS_RDONLY)) {
+ /* Read-only mode. Keep a copy for switching to rw mode */
+ c->rcvrd_mst_node = kmalloc(sz, GFP_KERNEL);
+ if (!c->rcvrd_mst_node) {
+ err = -ENOMEM;
+ goto out_free;
+ }
+ memcpy(c->rcvrd_mst_node, c->mst_node, UBIFS_MST_NODE_SZ);
+ }
+
+ vfree(buf2);
+ vfree(buf1);
+
+ return 0;
+
+out_err:
+ err = -EINVAL;
+out_free:
+ ubifs_err("failed to recover master node");
+ if (mst1) {
+ dbg_err("dumping first master node");
+ dbg_dump_node(c, mst1);
+ }
+ if (mst2) {
+ dbg_err("dumping second master node");
+ dbg_dump_node(c, mst2);
+ }
+ vfree(buf2);
+ vfree(buf1);
+ return err;
+}
+
+/**
+ * ubifs_write_rcvrd_mst_node - write the recovered master node.
+ * @c: UBIFS file-system description object
+ *
+ * This function writes the master node that was recovered during mounting in
+ * read-only mode and must now be written because we are remounting rw.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int ubifs_write_rcvrd_mst_node(struct ubifs_info *c)
+{
+ int err;
+
+ if (!c->rcvrd_mst_node)
+ return 0;
+ c->rcvrd_mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
+ c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
+ err = write_rcvrd_mst_node(c, c->rcvrd_mst_node);
+ if (err)
+ return err;
+ kfree(c->rcvrd_mst_node);
+ c->rcvrd_mst_node = NULL;
+ return 0;
+}
+
+/**
+ * is_last_write - determine if an offset was in the last write to a LEB.
+ * @c: UBIFS file-system description object
+ * @buf: buffer to check
+ * @offs: offset to check
+ *
+ * This function returns %1 if @offs was in the last write to the LEB whose data
+ * is in @buf, otherwise %0 is returned. The determination is made by checking
+ * for subsequent empty space starting from the next min_io_size boundary (or a
+ * bit less than the common header size if min_io_size is one).
+ */
+static int is_last_write(const struct ubifs_info *c, void *buf, int offs)
+{
+ int empty_offs;
+ int check_len;
+ uint8_t *p;
+
+ if (c->min_io_size == 1) {
+ check_len = c->leb_size - offs;
+ p = buf + check_len;
+ for (; check_len > 0; check_len--)
+ if (*--p != 0xff)
+ break;
+ /*
+ * 'check_len' is the size of the corruption which cannot be
+ * more than the size of 1 node if it was caused by an unclean
+ * unmount.
+ */
+ if (check_len > UBIFS_MAX_NODE_SZ)
+ return 0;
+ return 1;
+ }
+
+ /*
+ * Round up to the next c->min_io_size boundary i.e. 'offs' is in the
+ * last wbuf written. After that should be empty space.
+ */
+ empty_offs = ALIGN(offs + 1, c->min_io_size);
+ check_len = c->leb_size - empty_offs;
+ p = buf + empty_offs - offs;
+
+ for (; check_len > 0; check_len--)
+ if (*p++ != 0xff)
+ return 0;
+ return 1;
+}
+
+/**
+ * clean_buf - clean the data from an LEB sitting in a buffer.
+ * @c: UBIFS file-system description object
+ * @buf: buffer to clean
+ * @lnum: LEB number to clean
+ * @offs: offset from which to clean
+ * @len: length of buffer
+ *
+ * This function pads up to the next min_io_size boundary (if there is one) and
+ * sets empty space to all 0xff. @buf, @offs and @len are updated to the next
+ * min_io_size boundary (if there is one).
+ */
+static void clean_buf(const struct ubifs_info *c, void **buf, int lnum,
+ int *offs, int *len)
+{
+ int empty_offs, pad_len;
+
+ lnum = lnum;
+ dbg_rcvry("cleaning corruption at %d:%d", lnum, *offs);
+
+ if (c->min_io_size == 1) {
+ memset(*buf, 0xff, c->leb_size - *offs);
+ return;
+ }
+
+ ubifs_assert(!(*offs & 7));
+ empty_offs = ALIGN(*offs, c->min_io_size);
+ pad_len = empty_offs - *offs;
+ ubifs_pad(c, *buf, pad_len);
+ *offs += pad_len;
+ *buf += pad_len;
+ *len -= pad_len;
+ memset(*buf, 0xff, c->leb_size - empty_offs);
+}
+
+/**
+ * no_more_nodes - determine if there are no more nodes in a buffer.
+ * @c: UBIFS file-system description object
+ * @buf: buffer to check
+ * @len: length of buffer
+ * @lnum: LEB number of the LEB from which @buf was read
+ * @offs: offset from which @buf was read
+ *
+ * This function scans @buf for more nodes and returns %0 is a node is found and
+ * %1 if no more nodes are found.
+ */
+static int no_more_nodes(const struct ubifs_info *c, void *buf, int len,
+ int lnum, int offs)
+{
+ int skip, next_offs = 0;
+
+ if (len > UBIFS_DATA_NODE_SZ) {
+ struct ubifs_ch *ch = buf;
+ int dlen = le32_to_cpu(ch->len);
+
+ if (ch->node_type == UBIFS_DATA_NODE && dlen >= UBIFS_CH_SZ &&
+ dlen <= UBIFS_MAX_DATA_NODE_SZ)
+ /* The corrupt node looks like a data node */
+ next_offs = ALIGN(offs + dlen, 8);
+ }
+
+ if (c->min_io_size == 1)
+ skip = 8;
+ else
+ skip = ALIGN(offs + 1, c->min_io_size) - offs;
+
+ offs += skip;
+ buf += skip;
+ len -= skip;
+ while (len > 8) {
+ struct ubifs_ch *ch = buf;
+ uint32_t magic = le32_to_cpu(ch->magic);
+ int ret;
+
+ if (magic == UBIFS_NODE_MAGIC) {
+ ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 1);
+ if (ret == SCANNED_A_NODE || ret > 0) {
+ /*
+ * There is a small chance this is just data in
+ * a data node, so check that possibility. e.g.
+ * this is part of a file that itself contains
+ * a UBIFS image.
+ */
+ if (next_offs && offs + le32_to_cpu(ch->len) <=
+ next_offs)
+ continue;
+ dbg_rcvry("unexpected node at %d:%d", lnum,
+ offs);
+ return 0;
+ }
+ }
+ offs += 8;
+ buf += 8;
+ len -= 8;
+ }
+ return 1;
+}
+
+/**
+ * fix_unclean_leb - fix an unclean LEB.
+ * @c: UBIFS file-system description object
+ * @sleb: scanned LEB information
+ * @start: offset where scan started
+ */
+static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
+ int start)
+{
+ int lnum = sleb->lnum, endpt = start;
+
+ /* Get the end offset of the last node we are keeping */
+ if (!list_empty(&sleb->nodes)) {
+ struct ubifs_scan_node *snod;
+
+ snod = list_entry(sleb->nodes.prev,
+ struct ubifs_scan_node, list);
+ endpt = snod->offs + snod->len;
+ }
+
+ if ((c->vfs_sb->s_flags & MS_RDONLY) && !c->remounting_rw) {
+ /* Add to recovery list */
+ struct ubifs_unclean_leb *ucleb;
+
+ dbg_rcvry("need to fix LEB %d start %d endpt %d",
+ lnum, start, sleb->endpt);
+ ucleb = kzalloc(sizeof(struct ubifs_unclean_leb), GFP_NOFS);
+ if (!ucleb)
+ return -ENOMEM;
+ ucleb->lnum = lnum;
+ ucleb->endpt = endpt;
+ list_add_tail(&ucleb->list, &c->unclean_leb_list);
+ }
+ return 0;
+}
+
+/**
+ * drop_incomplete_group - drop nodes from an incomplete group.
+ * @sleb: scanned LEB information
+ * @offs: offset of dropped nodes is returned here
+ *
+ * This function returns %1 if nodes are dropped and %0 otherwise.
+ */
+static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs)
+{
+ int dropped = 0;
+
+ while (!list_empty(&sleb->nodes)) {
+ struct ubifs_scan_node *snod;
+ struct ubifs_ch *ch;
+
+ snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node,
+ list);
+ ch = snod->node;
+ if (ch->group_type != UBIFS_IN_NODE_GROUP)
+ return dropped;
+ dbg_rcvry("dropping node at %d:%d", sleb->lnum, snod->offs);
+ *offs = snod->offs;
+ list_del(&snod->list);
+ kfree(snod);
+ sleb->nodes_cnt -= 1;
+ dropped = 1;
+ }
+ return dropped;
+}
+
+/**
+ * ubifs_recover_leb - scan and recover a LEB.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number
+ * @offs: offset
+ * @sbuf: LEB-sized buffer to use
+ * @grouped: nodes may be grouped for recovery
+ *
+ * This function does a scan of a LEB, but caters for errors that might have
+ * been caused by the unclean unmount from which we are attempting to recover.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
+ int offs, void *sbuf, int grouped)
+{
+ int err, len = c->leb_size - offs, need_clean = 0, quiet = 1;
+ int empty_chkd = 0, start = offs;
+ struct ubifs_scan_leb *sleb;
+ void *buf = sbuf + offs;
+
+ dbg_rcvry("%d:%d", lnum, offs);
+
+ sleb = ubifs_start_scan(c, lnum, offs, sbuf);
+ if (IS_ERR(sleb))
+ return sleb;
+
+ if (sleb->ecc)
+ need_clean = 1;
+
+ while (len >= 8) {
+ int ret;
+
+ dbg_scan("look at LEB %d:%d (%d bytes left)",
+ lnum, offs, len);
+
+ cond_resched();
+
+ /*
+ * Scan quietly until there is an error from which we cannot
+ * recover
+ */
+ ret = ubifs_scan_a_node(c, buf, len, lnum, offs, quiet);
+
+ if (ret == SCANNED_A_NODE) {
+ /* A valid node, and not a padding node */
+ struct ubifs_ch *ch = buf;
+ int node_len;
+
+ err = ubifs_add_snod(c, sleb, buf, offs);
+ if (err)
+ goto error;
+ node_len = ALIGN(le32_to_cpu(ch->len), 8);
+ offs += node_len;
+ buf += node_len;
+ len -= node_len;
+ continue;
+ }
+
+ if (ret > 0) {
+ /* Padding bytes or a valid padding node */
+ offs += ret;
+ buf += ret;
+ len -= ret;
+ continue;
+ }
+
+ if (ret == SCANNED_EMPTY_SPACE) {
+ if (!is_empty(buf, len)) {
+ if (!is_last_write(c, buf, offs))
+ break;
+ clean_buf(c, &buf, lnum, &offs, &len);
+ need_clean = 1;
+ }
+ empty_chkd = 1;
+ break;
+ }
+
+ if (ret == SCANNED_GARBAGE || ret == SCANNED_A_BAD_PAD_NODE)
+ if (is_last_write(c, buf, offs)) {
+ clean_buf(c, &buf, lnum, &offs, &len);
+ need_clean = 1;
+ empty_chkd = 1;
+ break;
+ }
+
+ if (ret == SCANNED_A_CORRUPT_NODE)
+ if (no_more_nodes(c, buf, len, lnum, offs)) {
+ clean_buf(c, &buf, lnum, &offs, &len);
+ need_clean = 1;
+ empty_chkd = 1;
+ break;
+ }
+
+ if (quiet) {
+ /* Redo the last scan but noisily */
+ quiet = 0;
+ continue;
+ }
+
+ switch (ret) {
+ case SCANNED_GARBAGE:
+ dbg_err("garbage");
+ goto corrupted;
+ case SCANNED_A_CORRUPT_NODE:
+ case SCANNED_A_BAD_PAD_NODE:
+ dbg_err("bad node");
+ goto corrupted;
+ default:
+ dbg_err("unknown");
+ goto corrupted;
+ }
+ }
+
+ if (!empty_chkd && !is_empty(buf, len)) {
+ if (is_last_write(c, buf, offs)) {
+ clean_buf(c, &buf, lnum, &offs, &len);
+ need_clean = 1;
+ } else {
+ ubifs_err("corrupt empty space at LEB %d:%d",
+ lnum, offs);
+ goto corrupted;
+ }
+ }
+
+ /* Drop nodes from incomplete group */
+ if (grouped && drop_incomplete_group(sleb, &offs)) {
+ buf = sbuf + offs;
+ len = c->leb_size - offs;
+ clean_buf(c, &buf, lnum, &offs, &len);
+ need_clean = 1;
+ }
+
+ if (offs % c->min_io_size) {
+ clean_buf(c, &buf, lnum, &offs, &len);
+ need_clean = 1;
+ }
+
+ ubifs_end_scan(c, sleb, lnum, offs);
+
+ if (need_clean) {
+ err = fix_unclean_leb(c, sleb, start);
+ if (err)
+ goto error;
+ }
+
+ return sleb;
+
+corrupted:
+ ubifs_scanned_corruption(c, lnum, offs, buf);
+ err = -EUCLEAN;
+error:
+ ubifs_err("LEB %d scanning failed", lnum);
+ ubifs_scan_destroy(sleb);
+ return ERR_PTR(err);
+}
+
+/**
+ * get_cs_sqnum - get commit start sequence number.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number of commit start node
+ * @offs: offset of commit start node
+ * @cs_sqnum: commit start sequence number is returned here
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int get_cs_sqnum(struct ubifs_info *c, int lnum, int offs,
+ unsigned long long *cs_sqnum)
+{
+ struct ubifs_cs_node *cs_node = NULL;
+ int err, ret;
+
+ dbg_rcvry("at %d:%d", lnum, offs);
+ cs_node = kmalloc(UBIFS_CS_NODE_SZ, GFP_KERNEL);
+ if (!cs_node)
+ return -ENOMEM;
+ if (c->leb_size - offs < UBIFS_CS_NODE_SZ)
+ goto out_err;
+ err = ubi_read(c->ubi, lnum, (void *)cs_node, offs, UBIFS_CS_NODE_SZ);
+ if (err && err != -EBADMSG)
+ goto out_free;
+ ret = ubifs_scan_a_node(c, cs_node, UBIFS_CS_NODE_SZ, lnum, offs, 0);
+ if (ret != SCANNED_A_NODE) {
+ dbg_err("Not a valid node");
+ goto out_err;
+ }
+ if (cs_node->ch.node_type != UBIFS_CS_NODE) {
+ dbg_err("Node a CS node, type is %d", cs_node->ch.node_type);
+ goto out_err;
+ }
+ if (le64_to_cpu(cs_node->cmt_no) != c->cmt_no) {
+ dbg_err("CS node cmt_no %llu != current cmt_no %llu",
+ (unsigned long long)le64_to_cpu(cs_node->cmt_no),
+ c->cmt_no);
+ goto out_err;
+ }
+ *cs_sqnum = le64_to_cpu(cs_node->ch.sqnum);
+ dbg_rcvry("commit start sqnum %llu", *cs_sqnum);
+ kfree(cs_node);
+ return 0;
+
+out_err:
+ err = -EINVAL;
+out_free:
+ ubifs_err("failed to get CS sqnum");
+ kfree(cs_node);
+ return err;
+}
+
+/**
+ * ubifs_recover_log_leb - scan and recover a log LEB.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number
+ * @offs: offset
+ * @sbuf: LEB-sized buffer to use
+ *
+ * This function does a scan of a LEB, but caters for errors that might have
+ * been caused by the unclean unmount from which we are attempting to recover.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
+ int offs, void *sbuf)
+{
+ struct ubifs_scan_leb *sleb;
+ int next_lnum;
+
+ dbg_rcvry("LEB %d", lnum);
+ next_lnum = lnum + 1;
+ if (next_lnum >= UBIFS_LOG_LNUM + c->log_lebs)
+ next_lnum = UBIFS_LOG_LNUM;
+ if (next_lnum != c->ltail_lnum) {
+ /*
+ * We can only recover at the end of the log, so check that the
+ * next log LEB is empty or out of date.
+ */
+ sleb = ubifs_scan(c, next_lnum, 0, sbuf);
+ if (IS_ERR(sleb))
+ return sleb;
+ if (sleb->nodes_cnt) {
+ struct ubifs_scan_node *snod;
+ unsigned long long cs_sqnum = c->cs_sqnum;
+
+ snod = list_entry(sleb->nodes.next,
+ struct ubifs_scan_node, list);
+ if (cs_sqnum == 0) {
+ int err;
+
+ err = get_cs_sqnum(c, lnum, offs, &cs_sqnum);
+ if (err) {
+ ubifs_scan_destroy(sleb);
+ return ERR_PTR(err);
+ }
+ }
+ if (snod->sqnum > cs_sqnum) {
+ ubifs_err("unrecoverable log corruption "
+ "in LEB %d", lnum);
+ ubifs_scan_destroy(sleb);
+ return ERR_PTR(-EUCLEAN);
+ }
+ }
+ ubifs_scan_destroy(sleb);
+ }
+ return ubifs_recover_leb(c, lnum, offs, sbuf, 0);
+}
+
+/**
+ * recover_head - recover a head.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number of head to recover
+ * @offs: offset of head to recover
+ * @sbuf: LEB-sized buffer to use
+ *
+ * This function ensures that there is no data on the flash at a head location.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int recover_head(const struct ubifs_info *c, int lnum, int offs,
+ void *sbuf)
+{
+ int len, err, need_clean = 0;
+
+ if (c->min_io_size > 1)
+ len = c->min_io_size;
+ else
+ len = 512;
+ if (offs + len > c->leb_size)
+ len = c->leb_size - offs;
+
+ if (!len)
+ return 0;
+
+ /* Read at the head location and check it is empty flash */
+ err = ubi_read(c->ubi, lnum, sbuf, offs, len);
+ if (err)
+ need_clean = 1;
+ else {
+ uint8_t *p = sbuf;
+
+ while (len--)
+ if (*p++ != 0xff) {
+ need_clean = 1;
+ break;
+ }
+ }
+
+ if (need_clean) {
+ dbg_rcvry("cleaning head at %d:%d", lnum, offs);
+ if (offs == 0)
+ return ubifs_leb_unmap(c, lnum);
+ err = ubi_read(c->ubi, lnum, sbuf, 0, offs);
+ if (err)
+ return err;
+ return ubi_leb_change(c->ubi, lnum, sbuf, offs, UBI_UNKNOWN);
+ }
+
+ return 0;
+}
+
+/**
+ * ubifs_recover_inl_heads - recover index and LPT heads.
+ * @c: UBIFS file-system description object
+ * @sbuf: LEB-sized buffer to use
+ *
+ * This function ensures that there is no data on the flash at the index and
+ * LPT head locations.
+ *
+ * This deals with the recovery of a half-completed journal commit. UBIFS is
+ * careful never to overwrite the last version of the index or the LPT. Because
+ * the index and LPT are wandering trees, data from a half-completed commit will
+ * not be referenced anywhere in UBIFS. The data will be either in LEBs that are
+ * assumed to be empty and will be unmapped anyway before use, or in the index
+ * and LPT heads.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf)
+{
+ int err;
+
+ ubifs_assert(!(c->vfs_sb->s_flags & MS_RDONLY) || c->remounting_rw);
+
+ dbg_rcvry("checking index head at %d:%d", c->ihead_lnum, c->ihead_offs);
+ err = recover_head(c, c->ihead_lnum, c->ihead_offs, sbuf);
+ if (err)
+ return err;
+
+ dbg_rcvry("checking LPT head at %d:%d", c->nhead_lnum, c->nhead_offs);
+ err = recover_head(c, c->nhead_lnum, c->nhead_offs, sbuf);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+/**
+ * clean_an_unclean_leb - read and write a LEB to remove corruption.
+ * @c: UBIFS file-system description object
+ * @ucleb: unclean LEB information
+ * @sbuf: LEB-sized buffer to use
+ *
+ * This function reads a LEB up to a point pre-determined by the mount recovery,
+ * checks the nodes, and writes the result back to the flash, thereby cleaning
+ * off any following corruption, or non-fatal ECC errors.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int clean_an_unclean_leb(const struct ubifs_info *c,
+ struct ubifs_unclean_leb *ucleb, void *sbuf)
+{
+ int err, lnum = ucleb->lnum, offs = 0, len = ucleb->endpt, quiet = 1;
+ void *buf = sbuf;
+
+ dbg_rcvry("LEB %d len %d", lnum, len);
+
+ if (len == 0) {
+ /* Nothing to read, just unmap it */
+ err = ubifs_leb_unmap(c, lnum);
+ if (err)
+ return err;
+ return 0;
+ }
+
+ err = ubi_read(c->ubi, lnum, buf, offs, len);
+ if (err && err != -EBADMSG)
+ return err;
+
+ while (len >= 8) {
+ int ret;
+
+ cond_resched();
+
+ /* Scan quietly until there is an error */
+ ret = ubifs_scan_a_node(c, buf, len, lnum, offs, quiet);
+
+ if (ret == SCANNED_A_NODE) {
+ /* A valid node, and not a padding node */
+ struct ubifs_ch *ch = buf;
+ int node_len;
+
+ node_len = ALIGN(le32_to_cpu(ch->len), 8);
+ offs += node_len;
+ buf += node_len;
+ len -= node_len;
+ continue;
+ }
+
+ if (ret > 0) {
+ /* Padding bytes or a valid padding node */
+ offs += ret;
+ buf += ret;
+ len -= ret;
+ continue;
+ }
+
+ if (ret == SCANNED_EMPTY_SPACE) {
+ ubifs_err("unexpected empty space at %d:%d",
+ lnum, offs);
+ return -EUCLEAN;
+ }
+
+ if (quiet) {
+ /* Redo the last scan but noisily */
+ quiet = 0;
+ continue;
+ }
+
+ ubifs_scanned_corruption(c, lnum, offs, buf);
+ return -EUCLEAN;
+ }
+
+ /* Pad to min_io_size */
+ len = ALIGN(ucleb->endpt, c->min_io_size);
+ if (len > ucleb->endpt) {
+ int pad_len = len - ALIGN(ucleb->endpt, 8);
+
+ if (pad_len > 0) {
+ buf = c->sbuf + len - pad_len;
+ ubifs_pad(c, buf, pad_len);
+ }
+ }
+
+ /* Write back the LEB atomically */
+ err = ubi_leb_change(c->ubi, lnum, sbuf, len, UBI_UNKNOWN);
+ if (err)
+ return err;
+
+ dbg_rcvry("cleaned LEB %d", lnum);
+
+ return 0;
+}
+
+/**
+ * ubifs_clean_lebs - clean LEBs recovered during read-only mount.
+ * @c: UBIFS file-system description object
+ * @sbuf: LEB-sized buffer to use
+ *
+ * This function cleans a LEB identified during recovery that needs to be
+ * written but was not because UBIFS was mounted read-only. This happens when
+ * remounting to read-write mode.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf)
+{
+ dbg_rcvry("recovery");
+ while (!list_empty(&c->unclean_leb_list)) {
+ struct ubifs_unclean_leb *ucleb;
+ int err;
+
+ ucleb = list_entry(c->unclean_leb_list.next,
+ struct ubifs_unclean_leb, list);
+ err = clean_an_unclean_leb(c, ucleb, sbuf);
+ if (err)
+ return err;
+ list_del(&ucleb->list);
+ kfree(ucleb);
+ }
+ return 0;
+}
+
+/**
+ * struct size_entry - inode size information for recovery.
+ * @rb: link in the RB-tree of sizes
+ * @inum: inode number
+ * @i_size: size on inode
+ * @d_size: maximum size based on data nodes
+ * @exists: indicates whether the inode exists
+ * @inode: inode if pinned in memory awaiting rw mode to fix it
+ */
+struct size_entry {
+ struct rb_node rb;
+ ino_t inum;
+ loff_t i_size;
+ loff_t d_size;
+ int exists;
+ struct inode *inode;
+};
+
+/**
+ * add_ino - add an entry to the size tree.
+ * @c: UBIFS file-system description object
+ * @inum: inode number
+ * @i_size: size on inode
+ * @d_size: maximum size based on data nodes
+ * @exists: indicates whether the inode exists
+ */
+static int add_ino(struct ubifs_info *c, ino_t inum, loff_t i_size,
+ loff_t d_size, int exists)
+{
+ struct rb_node **p = &c->size_tree.rb_node, *parent = NULL;
+ struct size_entry *e;
+
+ while (*p) {
+ parent = *p;
+ e = rb_entry(parent, struct size_entry, rb);
+ if (inum < e->inum)
+ p = &(*p)->rb_left;
+ else
+ p = &(*p)->rb_right;
+ }
+
+ e = kzalloc(sizeof(struct size_entry), GFP_KERNEL);
+ if (!e)
+ return -ENOMEM;
+
+ e->inum = inum;
+ e->i_size = i_size;
+ e->d_size = d_size;
+ e->exists = exists;
+
+ rb_link_node(&e->rb, parent, p);
+ rb_insert_color(&e->rb, &c->size_tree);
+
+ return 0;
+}
+
+/**
+ * find_ino - find an entry on the size tree.
+ * @c: UBIFS file-system description object
+ * @inum: inode number
+ */
+static struct size_entry *find_ino(struct ubifs_info *c, ino_t inum)
+{
+ struct rb_node *p = c->size_tree.rb_node;
+ struct size_entry *e;
+
+ while (p) {
+ e = rb_entry(p, struct size_entry, rb);
+ if (inum < e->inum)
+ p = p->rb_left;
+ else if (inum > e->inum)
+ p = p->rb_right;
+ else
+ return e;
+ }
+ return NULL;
+}
+
+/**
+ * remove_ino - remove an entry from the size tree.
+ * @c: UBIFS file-system description object
+ * @inum: inode number
+ */
+static void remove_ino(struct ubifs_info *c, ino_t inum)
+{
+ struct size_entry *e = find_ino(c, inum);
+
+ if (!e)
+ return;
+ rb_erase(&e->rb, &c->size_tree);
+ kfree(e);
+}
+
+/**
+ * ubifs_recover_size_accum - accumulate inode sizes for recovery.
+ * @c: UBIFS file-system description object
+ * @key: node key
+ * @deletion: node is for a deletion
+ * @new_size: inode size
+ *
+ * This function has two purposes:
+ * 1) to ensure there are no data nodes that fall outside the inode size
+ * 2) to ensure there are no data nodes for inodes that do not exist
+ * To accomplish those purposes, a rb-tree is constructed containing an entry
+ * for each inode number in the journal that has not been deleted, and recording
+ * the size from the inode node, the maximum size of any data node (also altered
+ * by truncations) and a flag indicating a inode number for which no inode node
+ * was present in the journal.
+ *
+ * Note that there is still the possibility that there are data nodes that have
+ * been committed that are beyond the inode size, however the only way to find
+ * them would be to scan the entire index. Alternatively, some provision could
+ * be made to record the size of inodes at the start of commit, which would seem
+ * very cumbersome for a scenario that is quite unlikely and the only negative
+ * consequence of which is wasted space.
+ *
+ * This functions returns %0 on success and a negative error code on failure.
+ */
+int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key,
+ int deletion, loff_t new_size)
+{
+ ino_t inum = key_inum(c, key);
+ struct size_entry *e;
+ int err;
+
+ switch (key_type(c, key)) {
+ case UBIFS_INO_KEY:
+ if (deletion)
+ remove_ino(c, inum);
+ else {
+ e = find_ino(c, inum);
+ if (e) {
+ e->i_size = new_size;
+ e->exists = 1;
+ } else {
+ err = add_ino(c, inum, new_size, 0, 1);
+ if (err)
+ return err;
+ }
+ }
+ break;
+ case UBIFS_DATA_KEY:
+ e = find_ino(c, inum);
+ if (e) {
+ if (new_size > e->d_size)
+ e->d_size = new_size;
+ } else {
+ err = add_ino(c, inum, 0, new_size, 0);
+ if (err)
+ return err;
+ }
+ break;
+ case UBIFS_TRUN_KEY:
+ e = find_ino(c, inum);
+ if (e)
+ e->d_size = new_size;
+ break;
+ }
+ return 0;
+}
+
+/**
+ * ubifs_recover_size - recover inode size.
+ * @c: UBIFS file-system description object
+ *
+ * This function attempts to fix inode size discrepancies identified by the
+ * 'ubifs_recover_size_accum()' function.
+ *
+ * This functions returns %0 on success and a negative error code on failure.
+ */
+int ubifs_recover_size(struct ubifs_info *c)
+{
+ struct rb_node *this = rb_first(&c->size_tree);
+
+ while (this) {
+ struct size_entry *e;
+ int err;
+
+ e = rb_entry(this, struct size_entry, rb);
+ if (!e->exists) {
+ union ubifs_key key;
+
+ ino_key_init(c, &key, e->inum);
+ err = ubifs_tnc_lookup(c, &key, c->sbuf);
+ if (err && err != -ENOENT)
+ return err;
+ if (err == -ENOENT) {
+ /* Remove data nodes that have no inode */
+ dbg_rcvry("removing ino %lu",
+ (unsigned long)e->inum);
+ err = ubifs_tnc_remove_ino(c, e->inum);
+ if (err)
+ return err;
+ } else {
+ struct ubifs_ino_node *ino = c->sbuf;
+
+ e->exists = 1;
+ e->i_size = le64_to_cpu(ino->size);
+ }
+ }
+ if (e->exists && e->i_size < e->d_size) {
+ if (!e->inode && (c->vfs_sb->s_flags & MS_RDONLY)) {
+ /* Fix the inode size and pin it in memory */
+ struct inode *inode;
+
+ inode = ubifs_iget(c->vfs_sb, e->inum);
+ if (IS_ERR(inode))
+ return PTR_ERR(inode);
+ if (inode->i_size < e->d_size) {
+ dbg_rcvry("ino %lu size %lld -> %lld",
+ (unsigned long)e->inum,
+ e->d_size, inode->i_size);
+ inode->i_size = e->d_size;
+ ubifs_inode(inode)->ui_size = e->d_size;
+ e->inode = inode;
+ this = rb_next(this);
+ continue;
+ }
+ iput(inode);
+ }
+ }
+ this = rb_next(this);
+ rb_erase(&e->rb, &c->size_tree);
+ kfree(e);
+ }
+ return 0;
+}
diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
new file mode 100644
index 0000000..da33a14
--- /dev/null
+++ b/fs/ubifs/replay.c
@@ -0,0 +1,1070 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ * Artem Bityutskiy (Битюцкий Ðртём)
+ */
+
+/*
+ * This file contains journal replay code. It runs when the file-system is being
+ * mounted and requires no locking.
+ *
+ * The larger is the journal, the longer it takes to scan it, so the longer it
+ * takes to mount UBIFS. This is why the journal has limited size which may be
+ * changed depending on the system requirements. But a larger journal gives
+ * faster I/O speed because it writes the index less frequently. So this is a
+ * trade-off. Also, the journal is indexed by the in-memory index (TNC), so the
+ * larger is the journal, the more memory its index may consume.
+ */
+
+#include "ubifs.h"
+
+/*
+ * Replay flags.
+ *
+ * REPLAY_DELETION: node was deleted
+ * REPLAY_REF: node is a reference node
+ */
+enum {
+ REPLAY_DELETION = 1,
+ REPLAY_REF = 2,
+};
+
+/**
+ * struct replay_entry - replay tree entry.
+ * @lnum: logical eraseblock number of the node
+ * @offs: node offset
+ * @len: node length
+ * @sqnum: node sequence number
+ * @flags: replay flags
+ * @rb: links the replay tree
+ * @key: node key
+ * @nm: directory entry name
+ * @old_size: truncation old size
+ * @new_size: truncation new size
+ * @free: amount of free space in a bud
+ * @dirty: amount of dirty space in a bud from padding and deletion nodes
+ *
+ * UBIFS journal replay must compare node sequence numbers, which means it must
+ * build a tree of node information to insert into the TNC.
+ */
+struct replay_entry {
+ int lnum;
+ int offs;
+ int len;
+ unsigned long long sqnum;
+ int flags;
+ struct rb_node rb;
+ union ubifs_key key;
+ union {
+ struct qstr nm;
+ struct {
+ loff_t old_size;
+ loff_t new_size;
+ };
+ struct {
+ int free;
+ int dirty;
+ };
+ };
+};
+
+/**
+ * struct bud_entry - entry in the list of buds to replay.
+ * @list: next bud in the list
+ * @bud: bud description object
+ * @free: free bytes in the bud
+ * @sqnum: reference node sequence number
+ */
+struct bud_entry {
+ struct list_head list;
+ struct ubifs_bud *bud;
+ int free;
+ unsigned long long sqnum;
+};
+
+/**
+ * set_bud_lprops - set free and dirty space used by a bud.
+ * @c: UBIFS file-system description object
+ * @r: replay entry of bud
+ */
+static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r)
+{
+ const struct ubifs_lprops *lp;
+ int err = 0, dirty;
+
+ ubifs_get_lprops(c);
+
+ lp = ubifs_lpt_lookup_dirty(c, r->lnum);
+ if (IS_ERR(lp)) {
+ err = PTR_ERR(lp);
+ goto out;
+ }
+
+ dirty = lp->dirty;
+ if (r->offs == 0 && (lp->free != c->leb_size || lp->dirty != 0)) {
+ /*
+ * The LEB was added to the journal with a starting offset of
+ * zero which means the LEB must have been empty. The LEB
+ * property values should be lp->free == c->leb_size and
+ * lp->dirty == 0, but that is not the case. The reason is that
+ * the LEB was garbage collected. The garbage collector resets
+ * the free and dirty space without recording it anywhere except
+ * lprops, so if there is not a commit then lprops does not have
+ * that information next time the file system is mounted.
+ *
+ * We do not need to adjust free space because the scan has told
+ * us the exact value which is recorded in the replay entry as
+ * r->free.
+ *
+ * However we do need to subtract from the dirty space the
+ * amount of space that the garbage collector reclaimed, which
+ * is the whole LEB minus the amount of space that was free.
+ */
+ dbg_mnt("bud LEB %d was GC'd (%d free, %d dirty)", r->lnum,
+ lp->free, lp->dirty);
+ dbg_gc("bud LEB %d was GC'd (%d free, %d dirty)", r->lnum,
+ lp->free, lp->dirty);
+ dirty -= c->leb_size - lp->free;
+ /*
+ * If the replay order was perfect the dirty space would now be
+ * zero. The order is not perfect because the the journal heads
+ * race with each other. This is not a problem but is does mean
+ * that the dirty space may temporarily exceed c->leb_size
+ * during the replay.
+ */
+ if (dirty != 0)
+ dbg_msg("LEB %d lp: %d free %d dirty "
+ "replay: %d free %d dirty", r->lnum, lp->free,
+ lp->dirty, r->free, r->dirty);
+ }
+ lp = ubifs_change_lp(c, lp, r->free, dirty + r->dirty,
+ lp->flags | LPROPS_TAKEN, 0);
+ if (IS_ERR(lp)) {
+ err = PTR_ERR(lp);
+ goto out;
+ }
+out:
+ ubifs_release_lprops(c);
+ return err;
+}
+
+/**
+ * trun_remove_range - apply a replay entry for a truncation to the TNC.
+ * @c: UBIFS file-system description object
+ * @r: replay entry of truncation
+ */
+static int trun_remove_range(struct ubifs_info *c, struct replay_entry *r)
+{
+ unsigned min_blk, max_blk;
+ union ubifs_key min_key, max_key;
+ ino_t ino;
+
+ min_blk = r->new_size / UBIFS_BLOCK_SIZE;
+ if (r->new_size & (UBIFS_BLOCK_SIZE - 1))
+ min_blk += 1;
+
+ max_blk = r->old_size / UBIFS_BLOCK_SIZE;
+ if ((r->old_size & (UBIFS_BLOCK_SIZE - 1)) == 0)
+ max_blk -= 1;
+
+ ino = key_inum(c, &r->key);
+
+ data_key_init(c, &min_key, ino, min_blk);
+ data_key_init(c, &max_key, ino, max_blk);
+
+ return ubifs_tnc_remove_range(c, &min_key, &max_key);
+}
+
+/**
+ * apply_replay_entry - apply a replay entry to the TNC.
+ * @c: UBIFS file-system description object
+ * @r: replay entry to apply
+ *
+ * Apply a replay entry to the TNC.
+ */
+static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
+{
+ int err, deletion = ((r->flags & REPLAY_DELETION) != 0);
+
+ dbg_mnt("LEB %d:%d len %d flgs %d sqnum %llu %s", r->lnum,
+ r->offs, r->len, r->flags, r->sqnum, DBGKEY(&r->key));
+
+ /* Set c->replay_sqnum to help deal with dangling branches. */
+ c->replay_sqnum = r->sqnum;
+
+ if (r->flags & REPLAY_REF)
+ err = set_bud_lprops(c, r);
+ else if (is_hash_key(c, &r->key)) {
+ if (deletion)
+ err = ubifs_tnc_remove_nm(c, &r->key, &r->nm);
+ else
+ err = ubifs_tnc_add_nm(c, &r->key, r->lnum, r->offs,
+ r->len, &r->nm);
+ } else {
+ if (deletion)
+ switch (key_type(c, &r->key)) {
+ case UBIFS_INO_KEY:
+ {
+ ino_t inum = key_inum(c, &r->key);
+
+ err = ubifs_tnc_remove_ino(c, inum);
+ break;
+ }
+ case UBIFS_TRUN_KEY:
+ err = trun_remove_range(c, r);
+ break;
+ default:
+ err = ubifs_tnc_remove(c, &r->key);
+ break;
+ }
+ else
+ err = ubifs_tnc_add(c, &r->key, r->lnum, r->offs,
+ r->len);
+ if (err)
+ return err;
+
+ if (c->need_recovery)
+ err = ubifs_recover_size_accum(c, &r->key, deletion,
+ r->new_size);
+ }
+
+ return err;
+}
+
+/**
+ * destroy_replay_tree - destroy the replay.
+ * @c: UBIFS file-system description object
+ *
+ * Destroy the replay tree.
+ */
+static void destroy_replay_tree(struct ubifs_info *c)
+{
+ struct rb_node *this = c->replay_tree.rb_node;
+ struct replay_entry *r;
+
+ while (this) {
+ if (this->rb_left) {
+ this = this->rb_left;
+ continue;
+ } else if (this->rb_right) {
+ this = this->rb_right;
+ continue;
+ }
+ r = rb_entry(this, struct replay_entry, rb);
+ this = rb_parent(this);
+ if (this) {
+ if (this->rb_left == &r->rb)
+ this->rb_left = NULL;
+ else
+ this->rb_right = NULL;
+ }
+ if (is_hash_key(c, &r->key))
+ kfree((void *)r->nm.name);
+ kfree(r);
+ }
+ c->replay_tree = RB_ROOT;
+}
+
+/**
+ * apply_replay_tree - apply the replay tree to the TNC.
+ * @c: UBIFS file-system description object
+ *
+ * Apply the replay tree.
+ * Returns zero in case of success and a negative error code in case of
+ * failure.
+ */
+static int apply_replay_tree(struct ubifs_info *c)
+{
+ struct rb_node *this = rb_first(&c->replay_tree);
+
+ while (this) {
+ struct replay_entry *r;
+ int err;
+
+ cond_resched();
+
+ r = rb_entry(this, struct replay_entry, rb);
+ err = apply_replay_entry(c, r);
+ if (err)
+ return err;
+ this = rb_next(this);
+ }
+ return 0;
+}
+
+/**
+ * insert_node - insert a node to the replay tree.
+ * @c: UBIFS file-system description object
+ * @lnum: node logical eraseblock number
+ * @offs: node offset
+ * @len: node length
+ * @key: node key
+ * @sqnum: sequence number
+ * @deletion: non-zero if this is a deletion
+ * @used: number of bytes in use in a LEB
+ * @old_size: truncation old size
+ * @new_size: truncation new size
+ *
+ * This function inserts a scanned non-direntry node to the replay tree. The
+ * replay tree is an RB-tree containing @struct replay_entry elements which are
+ * indexed by the sequence number. The replay tree is applied at the very end
+ * of the replay process. Since the tree is sorted in sequence number order,
+ * the older modifications are applied first. This function returns zero in
+ * case of success and a negative error code in case of failure.
+ */
+static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
+ union ubifs_key *key, unsigned long long sqnum,
+ int deletion, int *used, loff_t old_size,
+ loff_t new_size)
+{
+ struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
+ struct replay_entry *r;
+
+ if (key_inum(c, key) >= c->highest_inum)
+ c->highest_inum = key_inum(c, key);
+
+ dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
+ while (*p) {
+ parent = *p;
+ r = rb_entry(parent, struct replay_entry, rb);
+ if (sqnum < r->sqnum) {
+ p = &(*p)->rb_left;
+ continue;
+ } else if (sqnum > r->sqnum) {
+ p = &(*p)->rb_right;
+ continue;
+ }
+ ubifs_err("duplicate sqnum in replay");
+ return -EINVAL;
+ }
+
+ r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
+ if (!r)
+ return -ENOMEM;
+
+ if (!deletion)
+ *used += ALIGN(len, 8);
+ r->lnum = lnum;
+ r->offs = offs;
+ r->len = len;
+ r->sqnum = sqnum;
+ r->flags = (deletion ? REPLAY_DELETION : 0);
+ r->old_size = old_size;
+ r->new_size = new_size;
+ key_copy(c, key, &r->key);
+
+ rb_link_node(&r->rb, parent, p);
+ rb_insert_color(&r->rb, &c->replay_tree);
+ return 0;
+}
+
+/**
+ * insert_dent - insert a directory entry node into the replay tree.
+ * @c: UBIFS file-system description object
+ * @lnum: node logical eraseblock number
+ * @offs: node offset
+ * @len: node length
+ * @key: node key
+ * @name: directory entry name
+ * @nlen: directory entry name length
+ * @sqnum: sequence number
+ * @deletion: non-zero if this is a deletion
+ * @used: number of bytes in use in a LEB
+ *
+ * This function inserts a scanned directory entry node to the replay tree.
+ * Returns zero in case of success and a negative error code in case of
+ * failure.
+ *
+ * This function is also used for extended attribute entries because they are
+ * implemented as directory entry nodes.
+ */
+static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
+ union ubifs_key *key, const char *name, int nlen,
+ unsigned long long sqnum, int deletion, int *used)
+{
+ struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
+ struct replay_entry *r;
+ char *nbuf;
+
+ if (key_inum(c, key) >= c->highest_inum)
+ c->highest_inum = key_inum(c, key);
+
+ dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
+ while (*p) {
+ parent = *p;
+ r = rb_entry(parent, struct replay_entry, rb);
+ if (sqnum < r->sqnum) {
+ p = &(*p)->rb_left;
+ continue;
+ }
+ if (sqnum > r->sqnum) {
+ p = &(*p)->rb_right;
+ continue;
+ }
+ ubifs_err("duplicate sqnum in replay");
+ return -EINVAL;
+ }
+
+ r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
+ if (!r)
+ return -ENOMEM;
+ nbuf = kmalloc(nlen + 1, GFP_KERNEL);
+ if (!nbuf) {
+ kfree(r);
+ return -ENOMEM;
+ }
+
+ if (!deletion)
+ *used += ALIGN(len, 8);
+ r->lnum = lnum;
+ r->offs = offs;
+ r->len = len;
+ r->sqnum = sqnum;
+ r->nm.len = nlen;
+ memcpy(nbuf, name, nlen);
+ nbuf[nlen] = '\0';
+ r->nm.name = nbuf;
+ r->flags = (deletion ? REPLAY_DELETION : 0);
+ key_copy(c, key, &r->key);
+
+ ubifs_assert(!*p);
+ rb_link_node(&r->rb, parent, p);
+ rb_insert_color(&r->rb, &c->replay_tree);
+ return 0;
+}
+
+/**
+ * ubifs_validate_entry - validate directory or extended attribute entry node.
+ * @c: UBIFS file-system description object
+ * @dent: the node to validate
+ *
+ * This function validates directory or extended attribute entry node @dent.
+ * Returns zero if the node is all right and a %-EINVAL if not.
+ */
+int ubifs_validate_entry(struct ubifs_info *c,
+ const struct ubifs_dent_node *dent)
+{
+ int key_type = key_type_flash(c, dent->key);
+ int nlen = le16_to_cpu(dent->nlen);
+
+ if (le32_to_cpu(dent->ch.len) != nlen + UBIFS_DENT_NODE_SZ + 1 ||
+ dent->type >= UBIFS_ITYPES_CNT ||
+ nlen > UBIFS_MAX_NLEN || dent->name[nlen] != 0 ||
+ strnlen((char *)dent->name, nlen) != nlen ||
+ le64_to_cpu(dent->inum) > MAX_INUM) {
+ ubifs_err("bad %s node", key_type == UBIFS_DENT_KEY ?
+ "directory entry" : "extended attribute entry");
+ return -EINVAL;
+ }
+
+ if (key_type != UBIFS_DENT_KEY && key_type != UBIFS_XENT_KEY) {
+ ubifs_err("bad key type %d", key_type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * replay_bud - replay a bud logical eraseblock.
+ * @c: UBIFS file-system description object
+ * @lnum: bud logical eraseblock number to replay
+ * @offs: bud start offset
+ * @jhead: journal head to which this bud belongs
+ * @free: amount of free space in the bud is returned here
+ * @dirty: amount of dirty space from padding and deletion nodes is returned
+ * here
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
+ int *free, int *dirty)
+{
+ int err = 0, used = 0;
+ struct ubifs_scan_leb *sleb;
+ struct ubifs_scan_node *snod;
+ struct ubifs_bud *bud;
+
+ dbg_mnt("replay bud LEB %d, head %d", lnum, jhead);
+ if (c->need_recovery)
+ sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf, jhead != GCHD);
+ else
+ sleb = ubifs_scan(c, lnum, offs, c->sbuf);
+ if (IS_ERR(sleb))
+ return PTR_ERR(sleb);
+
+ /*
+ * The bud does not have to start from offset zero - the beginning of
+ * the 'lnum' LEB may contain previously committed data. One of the
+ * things we have to do in replay is to correctly update lprops with
+ * newer information about this LEB.
+ *
+ * At this point lprops thinks that this LEB has 'c->leb_size - offs'
+ * bytes of free space because it only contain information about
+ * committed data.
+ *
+ * But we know that real amount of free space is 'c->leb_size -
+ * sleb->endpt', and the space in the 'lnum' LEB between 'offs' and
+ * 'sleb->endpt' is used by bud data. We have to correctly calculate
+ * how much of these data are dirty and update lprops with this
+ * information.
+ *
+ * The dirt in that LEB region is comprised of padding nodes, deletion
+ * nodes, truncation nodes and nodes which are obsoleted by subsequent
+ * nodes in this LEB. So instead of calculating clean space, we
+ * calculate used space ('used' variable).
+ */
+
+ list_for_each_entry(snod, &sleb->nodes, list) {
+ int deletion = 0;
+
+ cond_resched();
+
+ if (snod->sqnum >= SQNUM_WATERMARK) {
+ ubifs_err("file system's life ended");
+ goto out_dump;
+ }
+
+ if (snod->sqnum > c->max_sqnum)
+ c->max_sqnum = snod->sqnum;
+
+ switch (snod->type) {
+ case UBIFS_INO_NODE:
+ {
+ struct ubifs_ino_node *ino = snod->node;
+ loff_t new_size = le64_to_cpu(ino->size);
+
+ if (le32_to_cpu(ino->nlink) == 0)
+ deletion = 1;
+ err = insert_node(c, lnum, snod->offs, snod->len,
+ &snod->key, snod->sqnum, deletion,
+ &used, 0, new_size);
+ break;
+ }
+ case UBIFS_DATA_NODE:
+ {
+ struct ubifs_data_node *dn = snod->node;
+ loff_t new_size = le32_to_cpu(dn->size) +
+ key_block(c, &snod->key) *
+ UBIFS_BLOCK_SIZE;
+
+ err = insert_node(c, lnum, snod->offs, snod->len,
+ &snod->key, snod->sqnum, deletion,
+ &used, 0, new_size);
+ break;
+ }
+ case UBIFS_DENT_NODE:
+ case UBIFS_XENT_NODE:
+ {
+ struct ubifs_dent_node *dent = snod->node;
+
+ err = ubifs_validate_entry(c, dent);
+ if (err)
+ goto out_dump;
+
+ err = insert_dent(c, lnum, snod->offs, snod->len,
+ &snod->key, (char *)dent->name,
+ le16_to_cpu(dent->nlen), snod->sqnum,
+ !le64_to_cpu(dent->inum), &used);
+ break;
+ }
+ case UBIFS_TRUN_NODE:
+ {
+ struct ubifs_trun_node *trun = snod->node;
+ loff_t old_size = le64_to_cpu(trun->old_size);
+ loff_t new_size = le64_to_cpu(trun->new_size);
+ union ubifs_key key;
+
+ /* Validate truncation node */
+ if (old_size < 0 || old_size > c->max_inode_sz ||
+ new_size < 0 || new_size > c->max_inode_sz ||
+ old_size <= new_size) {
+ ubifs_err("bad truncation node");
+ goto out_dump;
+ }
+
+ /*
+ * Create a fake truncation key just to use the same
+ * functions which expect nodes to have keys.
+ */
+ trun_key_init(c, &key, le32_to_cpu(trun->inum));
+ err = insert_node(c, lnum, snod->offs, snod->len,
+ &key, snod->sqnum, 1, &used,
+ old_size, new_size);
+ break;
+ }
+ default:
+ ubifs_err("unexpected node type %d in bud LEB %d:%d",
+ snod->type, lnum, snod->offs);
+ err = -EINVAL;
+ goto out_dump;
+ }
+ if (err)
+ goto out;
+ }
+
+ bud = ubifs_search_bud(c, lnum);
+ if (!bud)
+ BUG();
+
+ ubifs_assert(sleb->endpt - offs >= used);
+ ubifs_assert(sleb->endpt % c->min_io_size == 0);
+
+ *dirty = sleb->endpt - offs - used;
+ *free = c->leb_size - sleb->endpt;
+
+out:
+ ubifs_scan_destroy(sleb);
+ return err;
+
+out_dump:
+ ubifs_err("bad node is at LEB %d:%d", lnum, snod->offs);
+ dbg_dump_node(c, snod->node);
+ ubifs_scan_destroy(sleb);
+ return -EINVAL;
+}
+
+/**
+ * insert_ref_node - insert a reference node to the replay tree.
+ * @c: UBIFS file-system description object
+ * @lnum: node logical eraseblock number
+ * @offs: node offset
+ * @sqnum: sequence number
+ * @free: amount of free space in bud
+ * @dirty: amount of dirty space from padding and deletion nodes
+ *
+ * This function inserts a reference node to the replay tree and returns zero
+ * in case of success or a negative error code in case of failure.
+ */
+static int insert_ref_node(struct ubifs_info *c, int lnum, int offs,
+ unsigned long long sqnum, int free, int dirty)
+{
+ struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
+ struct replay_entry *r;
+
+ dbg_mnt("add ref LEB %d:%d", lnum, offs);
+ while (*p) {
+ parent = *p;
+ r = rb_entry(parent, struct replay_entry, rb);
+ if (sqnum < r->sqnum) {
+ p = &(*p)->rb_left;
+ continue;
+ } else if (sqnum > r->sqnum) {
+ p = &(*p)->rb_right;
+ continue;
+ }
+ ubifs_err("duplicate sqnum in replay tree");
+ return -EINVAL;
+ }
+
+ r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
+ if (!r)
+ return -ENOMEM;
+
+ r->lnum = lnum;
+ r->offs = offs;
+ r->sqnum = sqnum;
+ r->flags = REPLAY_REF;
+ r->free = free;
+ r->dirty = dirty;
+
+ rb_link_node(&r->rb, parent, p);
+ rb_insert_color(&r->rb, &c->replay_tree);
+ return 0;
+}
+
+/**
+ * replay_buds - replay all buds.
+ * @c: UBIFS file-system description object
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int replay_buds(struct ubifs_info *c)
+{
+ struct bud_entry *b;
+ int err, uninitialized_var(free), uninitialized_var(dirty);
+
+ list_for_each_entry(b, &c->replay_buds, list) {
+ err = replay_bud(c, b->bud->lnum, b->bud->start, b->bud->jhead,
+ &free, &dirty);
+ if (err)
+ return err;
+ err = insert_ref_node(c, b->bud->lnum, b->bud->start, b->sqnum,
+ free, dirty);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+/**
+ * destroy_bud_list - destroy the list of buds to replay.
+ * @c: UBIFS file-system description object
+ */
+static void destroy_bud_list(struct ubifs_info *c)
+{
+ struct bud_entry *b;
+
+ while (!list_empty(&c->replay_buds)) {
+ b = list_entry(c->replay_buds.next, struct bud_entry, list);
+ list_del(&b->list);
+ kfree(b);
+ }
+}
+
+/**
+ * add_replay_bud - add a bud to the list of buds to replay.
+ * @c: UBIFS file-system description object
+ * @lnum: bud logical eraseblock number to replay
+ * @offs: bud start offset
+ * @jhead: journal head to which this bud belongs
+ * @sqnum: reference node sequence number
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int add_replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
+ unsigned long long sqnum)
+{
+ struct ubifs_bud *bud;
+ struct bud_entry *b;
+
+ dbg_mnt("add replay bud LEB %d:%d, head %d", lnum, offs, jhead);
+
+ bud = kmalloc(sizeof(struct ubifs_bud), GFP_KERNEL);
+ if (!bud)
+ return -ENOMEM;
+
+ b = kmalloc(sizeof(struct bud_entry), GFP_KERNEL);
+ if (!b) {
+ kfree(bud);
+ return -ENOMEM;
+ }
+
+ bud->lnum = lnum;
+ bud->start = offs;
+ bud->jhead = jhead;
+ ubifs_add_bud(c, bud);
+
+ b->bud = bud;
+ b->sqnum = sqnum;
+ list_add_tail(&b->list, &c->replay_buds);
+
+ return 0;
+}
+
+/**
+ * validate_ref - validate a reference node.
+ * @c: UBIFS file-system description object
+ * @ref: the reference node to validate
+ * @ref_lnum: LEB number of the reference node
+ * @ref_offs: reference node offset
+ *
+ * This function returns %1 if a bud reference already exists for the LEB. %0 is
+ * returned if the reference node is new, otherwise %-EINVAL is returned if
+ * validation failed.
+ */
+static int validate_ref(struct ubifs_info *c, const struct ubifs_ref_node *ref)
+{
+ struct ubifs_bud *bud;
+ int lnum = le32_to_cpu(ref->lnum);
+ unsigned int offs = le32_to_cpu(ref->offs);
+ unsigned int jhead = le32_to_cpu(ref->jhead);
+
+ /*
+ * ref->offs may point to the end of LEB when the journal head points
+ * to the end of LEB and we write reference node for it during commit.
+ * So this is why we require 'offs > c->leb_size'.
+ */
+ if (jhead >= c->jhead_cnt || lnum >= c->leb_cnt ||
+ lnum < c->main_first || offs > c->leb_size ||
+ offs & (c->min_io_size - 1))
+ return -EINVAL;
+
+ /* Make sure we have not already looked at this bud */
+ bud = ubifs_search_bud(c, lnum);
+ if (bud) {
+ if (bud->jhead == jhead && bud->start <= offs)
+ return 1;
+ ubifs_err("bud at LEB %d:%d was already referred", lnum, offs);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * replay_log_leb - replay a log logical eraseblock.
+ * @c: UBIFS file-system description object
+ * @lnum: log logical eraseblock to replay
+ * @offs: offset to start replaying from
+ * @sbuf: scan buffer
+ *
+ * This function replays a log LEB and returns zero in case of success, %1 if
+ * this is the last LEB in the log, and a negative error code in case of
+ * failure.
+ */
+static int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf)
+{
+ int err;
+ struct ubifs_scan_leb *sleb;
+ struct ubifs_scan_node *snod;
+ const struct ubifs_cs_node *node;
+
+ dbg_mnt("replay log LEB %d:%d", lnum, offs);
+ sleb = ubifs_scan(c, lnum, offs, sbuf);
+ if (IS_ERR(sleb)) {
+ if (c->need_recovery)
+ sleb = ubifs_recover_log_leb(c, lnum, offs, sbuf);
+ if (IS_ERR(sleb))
+ return PTR_ERR(sleb);
+ }
+
+ if (sleb->nodes_cnt == 0) {
+ err = 1;
+ goto out;
+ }
+
+ node = sleb->buf;
+
+ snod = list_entry(sleb->nodes.next, struct ubifs_scan_node, list);
+ if (c->cs_sqnum == 0) {
+ /*
+ * This is the first log LEB we are looking at, make sure that
+ * the first node is a commit start node. Also record its
+ * sequence number so that UBIFS can determine where the log
+ * ends, because all nodes which were have higher sequence
+ * numbers.
+ */
+ if (snod->type != UBIFS_CS_NODE) {
+ dbg_err("first log node at LEB %d:%d is not CS node",
+ lnum, offs);
+ goto out_dump;
+ }
+ if (le64_to_cpu(node->cmt_no) != c->cmt_no) {
+ dbg_err("first CS node at LEB %d:%d has wrong "
+ "commit number %llu expected %llu",
+ lnum, offs,
+ (unsigned long long)le64_to_cpu(node->cmt_no),
+ c->cmt_no);
+ goto out_dump;
+ }
+
+ c->cs_sqnum = le64_to_cpu(node->ch.sqnum);
+ dbg_mnt("commit start sqnum %llu", c->cs_sqnum);
+ }
+
+ if (snod->sqnum < c->cs_sqnum) {
+ /*
+ * This means that we reached end of log and now
+ * look to the older log data, which was already
+ * committed but the eraseblock was not erased (UBIFS
+ * only un-maps it). So this basically means we have to
+ * exit with "end of log" code.
+ */
+ err = 1;
+ goto out;
+ }
+
+ /* Make sure the first node sits at offset zero of the LEB */
+ if (snod->offs != 0) {
+ dbg_err("first node is not at zero offset");
+ goto out_dump;
+ }
+
+ list_for_each_entry(snod, &sleb->nodes, list) {
+
+ cond_resched();
+
+ if (snod->sqnum >= SQNUM_WATERMARK) {
+ ubifs_err("file system's life ended");
+ goto out_dump;
+ }
+
+ if (snod->sqnum < c->cs_sqnum) {
+ dbg_err("bad sqnum %llu, commit sqnum %llu",
+ snod->sqnum, c->cs_sqnum);
+ goto out_dump;
+ }
+
+ if (snod->sqnum > c->max_sqnum)
+ c->max_sqnum = snod->sqnum;
+
+ switch (snod->type) {
+ case UBIFS_REF_NODE: {
+ const struct ubifs_ref_node *ref = snod->node;
+
+ err = validate_ref(c, ref);
+ if (err == 1)
+ break; /* Already have this bud */
+ if (err)
+ goto out_dump;
+
+ err = add_replay_bud(c, le32_to_cpu(ref->lnum),
+ le32_to_cpu(ref->offs),
+ le32_to_cpu(ref->jhead),
+ snod->sqnum);
+ if (err)
+ goto out;
+
+ break;
+ }
+ case UBIFS_CS_NODE:
+ /* Make sure it sits at the beginning of LEB */
+ if (snod->offs != 0) {
+ ubifs_err("unexpected node in log");
+ goto out_dump;
+ }
+ break;
+ default:
+ ubifs_err("unexpected node in log");
+ goto out_dump;
+ }
+ }
+
+ if (sleb->endpt || c->lhead_offs >= c->leb_size) {
+ c->lhead_lnum = lnum;
+ c->lhead_offs = sleb->endpt;
+ }
+
+ err = !sleb->endpt;
+out:
+ ubifs_scan_destroy(sleb);
+ return err;
+
+out_dump:
+ ubifs_err("log error detected while replying the log at LEB %d:%d",
+ lnum, offs + snod->offs);
+ dbg_dump_node(c, snod->node);
+ ubifs_scan_destroy(sleb);
+ return -EINVAL;
+}
+
+/**
+ * take_ihead - update the status of the index head in lprops to 'taken'.
+ * @c: UBIFS file-system description object
+ *
+ * This function returns the amount of free space in the index head LEB or a
+ * negative error code.
+ */
+static int take_ihead(struct ubifs_info *c)
+{
+ const struct ubifs_lprops *lp;
+ int err, free;
+
+ ubifs_get_lprops(c);
+
+ lp = ubifs_lpt_lookup_dirty(c, c->ihead_lnum);
+ if (IS_ERR(lp)) {
+ err = PTR_ERR(lp);
+ goto out;
+ }
+
+ free = lp->free;
+
+ lp = ubifs_change_lp(c, lp, LPROPS_NC, LPROPS_NC,
+ lp->flags | LPROPS_TAKEN, 0);
+ if (IS_ERR(lp)) {
+ err = PTR_ERR(lp);
+ goto out;
+ }
+
+ err = free;
+out:
+ ubifs_release_lprops(c);
+ return err;
+}
+
+/**
+ * ubifs_replay_journal - replay journal.
+ * @c: UBIFS file-system description object
+ *
+ * This function scans the journal, replays and cleans it up. It makes sure all
+ * memory data structures related to uncommitted journal are built (dirty TNC
+ * tree, tree of buds, modified lprops, etc).
+ */
+int ubifs_replay_journal(struct ubifs_info *c)
+{
+ int err, i, lnum, offs, _free;
+ void *sbuf = NULL;
+
+ BUILD_BUG_ON(UBIFS_TRUN_KEY > 5);
+
+ /* Update the status of the index head in lprops to 'taken' */
+ _free = take_ihead(c);
+ if (_free < 0)
+ return _free; /* Error code */
+
+ if (c->ihead_offs != c->leb_size - _free) {
+ ubifs_err("bad index head LEB %d:%d", c->ihead_lnum,
+ c->ihead_offs);
+ return -EINVAL;
+ }
+
+ sbuf = vmalloc(c->leb_size);
+ if (!sbuf)
+ return -ENOMEM;
+
+ dbg_mnt("start replaying the journal");
+
+ c->replaying = 1;
+
+ lnum = c->ltail_lnum = c->lhead_lnum;
+ offs = c->lhead_offs;
+
+ for (i = 0; i < c->log_lebs; i++, lnum++) {
+ if (lnum >= UBIFS_LOG_LNUM + c->log_lebs) {
+ /*
+ * The log is logically circular, we reached the last
+ * LEB, switch to the first one.
+ */
+ lnum = UBIFS_LOG_LNUM;
+ offs = 0;
+ }
+ err = replay_log_leb(c, lnum, offs, sbuf);
+ if (err == 1)
+ /* We hit the end of the log */
+ break;
+ if (err)
+ goto out;
+ offs = 0;
+ }
+
+ err = replay_buds(c);
+ if (err)
+ goto out;
+
+ err = apply_replay_tree(c);
+ if (err)
+ goto out;
+
+ ubifs_assert(c->bud_bytes <= c->max_bud_bytes || c->need_recovery);
+ dbg_mnt("finished, log head LEB %d:%d, max_sqnum %llu, "
+ "highest_inum %lu", c->lhead_lnum, c->lhead_offs, c->max_sqnum,
+ (unsigned long)c->highest_inum);
+out:
+ destroy_replay_tree(c);
+ destroy_bud_list(c);
+ vfree(sbuf);
+ c->replaying = 0;
+ return err;
+}
diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c
new file mode 100644
index 0000000..9708fda
--- /dev/null
+++ b/fs/ubifs/sb.c
@@ -0,0 +1,324 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Ðртём)
+ * Adrian Hunter
+ */
+
+/*
+ * This file implements UBIFS superblock. The superblock is stored at the first
+ * LEB of the volume and is never changed by UBIFS. Only user-space tools may
+ * change it. The superblock node mostly contains geometry information.
+ */
+
+#include "ubifs.h"
+
+/*
+ * Default journal size in logical eraseblocks as a percent of total
+ * flash size.
+ */
+#define DEFAULT_JNL_PERCENT 5
+
+/* Default maximum journal size in bytes */
+#define DEFAULT_MAX_JNL (32*1024*1024)
+
+/* Default indexing tree fanout */
+#define DEFAULT_FANOUT 8
+
+/* Default number of data journal heads */
+#define DEFAULT_JHEADS_CNT 1
+
+/* Default positions of different LEBs in the main area */
+#define DEFAULT_IDX_LEB 0
+#define DEFAULT_DATA_LEB 1
+#define DEFAULT_GC_LEB 2
+
+/* Default number of LEB numbers in LPT's save table */
+#define DEFAULT_LSAVE_CNT 256
+
+/* Default reserved pool size as a percent of maximum free space */
+#define DEFAULT_RP_PERCENT 5
+
+/* The default maximum size of reserved pool in bytes */
+#define DEFAULT_MAX_RP_SIZE (5*1024*1024)
+
+/* Default time granularity in nanoseconds */
+#define DEFAULT_TIME_GRAN 1000000000
+
+/**
+ * validate_sb - validate superblock node.
+ * @c: UBIFS file-system description object
+ * @sup: superblock node
+ *
+ * This function validates superblock node @sup. Since most of data was read
+ * from the superblock and stored in @c, the function validates fields in @c
+ * instead. Returns zero in case of success and %-EINVAL in case of validation
+ * failure.
+ */
+static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
+{
+ long long max_bytes;
+ int err = 1, min_leb_cnt;
+
+ if (!c->key_hash) {
+ err = 2;
+ goto failed;
+ }
+
+ if (sup->key_fmt != UBIFS_SIMPLE_KEY_FMT) {
+ err = 3;
+ goto failed;
+ }
+
+ if (le32_to_cpu(sup->min_io_size) != c->min_io_size) {
+ ubifs_err("min. I/O unit mismatch: %d in superblock, %d real",
+ le32_to_cpu(sup->min_io_size), c->min_io_size);
+ goto failed;
+ }
+
+ if (le32_to_cpu(sup->leb_size) != c->leb_size) {
+ ubifs_err("LEB size mismatch: %d in superblock, %d real",
+ le32_to_cpu(sup->leb_size), c->leb_size);
+ goto failed;
+ }
+
+ if (c->log_lebs < UBIFS_MIN_LOG_LEBS ||
+ c->lpt_lebs < UBIFS_MIN_LPT_LEBS ||
+ c->orph_lebs < UBIFS_MIN_ORPH_LEBS ||
+ c->main_lebs < UBIFS_MIN_MAIN_LEBS) {
+ err = 4;
+ goto failed;
+ }
+
+ /*
+ * Calculate minimum allowed amount of main area LEBs. This is very
+ * similar to %UBIFS_MIN_LEB_CNT, but we take into account real what we
+ * have just read from the superblock.
+ */
+ min_leb_cnt = UBIFS_SB_LEBS + UBIFS_MST_LEBS + c->log_lebs;
+ min_leb_cnt += c->lpt_lebs + c->orph_lebs + c->jhead_cnt + 6;
+
+ if (c->leb_cnt < min_leb_cnt || c->leb_cnt > c->vi.size) {
+ ubifs_err("bad LEB count: %d in superblock, %d on UBI volume, "
+ "%d minimum required", c->leb_cnt, c->vi.size,
+ min_leb_cnt);
+ goto failed;
+ }
+
+ if (c->max_leb_cnt < c->leb_cnt) {
+ ubifs_err("max. LEB count %d less than LEB count %d",
+ c->max_leb_cnt, c->leb_cnt);
+ goto failed;
+ }
+
+ if (c->main_lebs < UBIFS_MIN_MAIN_LEBS) {
+ err = 7;
+ goto failed;
+ }
+
+ if (c->max_bud_bytes < (long long)c->leb_size * UBIFS_MIN_BUD_LEBS ||
+ c->max_bud_bytes > (long long)c->leb_size * c->main_lebs) {
+ err = 8;
+ goto failed;
+ }
+
+ if (c->jhead_cnt < NONDATA_JHEADS_CNT + 1 ||
+ c->jhead_cnt > NONDATA_JHEADS_CNT + UBIFS_MAX_JHEADS) {
+ err = 9;
+ goto failed;
+ }
+
+ if (c->fanout < UBIFS_MIN_FANOUT ||
+ ubifs_idx_node_sz(c, c->fanout) > c->leb_size) {
+ err = 10;
+ goto failed;
+ }
+
+ if (c->lsave_cnt < 0 || (c->lsave_cnt > DEFAULT_LSAVE_CNT &&
+ c->lsave_cnt > c->max_leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS -
+ c->log_lebs - c->lpt_lebs - c->orph_lebs)) {
+ err = 11;
+ goto failed;
+ }
+
+ if (UBIFS_SB_LEBS + UBIFS_MST_LEBS + c->log_lebs + c->lpt_lebs +
+ c->orph_lebs + c->main_lebs != c->leb_cnt) {
+ err = 12;
+ goto failed;
+ }
+
+ if (c->default_compr < 0 || c->default_compr >= UBIFS_COMPR_TYPES_CNT) {
+ err = 13;
+ goto failed;
+ }
+
+ max_bytes = c->main_lebs * (long long)c->leb_size;
+ if (c->rp_size < 0 || max_bytes < c->rp_size) {
+ err = 14;
+ goto failed;
+ }
+
+ if (le32_to_cpu(sup->time_gran) > 1000000000 ||
+ le32_to_cpu(sup->time_gran) < 1) {
+ err = 15;
+ goto failed;
+ }
+
+ return 0;
+
+failed:
+ ubifs_err("bad superblock, error %d", err);
+ dbg_dump_node(c, sup);
+ return -EINVAL;
+}
+
+/**
+ * ubifs_read_sb_node - read superblock node.
+ * @c: UBIFS file-system description object
+ *
+ * This function returns a pointer to the superblock node or a negative error
+ * code.
+ */
+struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c)
+{
+ struct ubifs_sb_node *sup;
+ int err;
+
+ sup = kmalloc(ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size), GFP_NOFS);
+ if (!sup)
+ return ERR_PTR(-ENOMEM);
+
+ err = ubifs_read_node(c, sup, UBIFS_SB_NODE, UBIFS_SB_NODE_SZ,
+ UBIFS_SB_LNUM, 0);
+ if (err) {
+ kfree(sup);
+ return ERR_PTR(err);
+ }
+
+ return sup;
+}
+
+/**
+ * ubifs_read_superblock - read superblock.
+ * @c: UBIFS file-system description object
+ *
+ * This function finds, reads and checks the superblock. If an empty UBI volume
+ * is being mounted, this function creates default superblock. Returns zero in
+ * case of success, and a negative error code in case of failure.
+ */
+int ubifs_read_superblock(struct ubifs_info *c)
+{
+ int err, sup_flags;
+ struct ubifs_sb_node *sup;
+
+ if (c->empty) {
+ printf("No UBIFS filesystem found!\n");
+ return -1;
+ }
+
+ sup = ubifs_read_sb_node(c);
+ if (IS_ERR(sup))
+ return PTR_ERR(sup);
+
+ /*
+ * The software supports all previous versions but not future versions,
+ * due to the unavailability of time-travelling equipment.
+ */
+ c->fmt_version = le32_to_cpu(sup->fmt_version);
+ if (c->fmt_version > UBIFS_FORMAT_VERSION) {
+ ubifs_err("on-flash format version is %d, but software only "
+ "supports up to version %d", c->fmt_version,
+ UBIFS_FORMAT_VERSION);
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (c->fmt_version < 3) {
+ ubifs_err("on-flash format version %d is not supported",
+ c->fmt_version);
+ err = -EINVAL;
+ goto out;
+ }
+
+ switch (sup->key_hash) {
+ case UBIFS_KEY_HASH_R5:
+ c->key_hash = key_r5_hash;
+ c->key_hash_type = UBIFS_KEY_HASH_R5;
+ break;
+
+ case UBIFS_KEY_HASH_TEST:
+ c->key_hash = key_test_hash;
+ c->key_hash_type = UBIFS_KEY_HASH_TEST;
+ break;
+ };
+
+ c->key_fmt = sup->key_fmt;
+
+ switch (c->key_fmt) {
+ case UBIFS_SIMPLE_KEY_FMT:
+ c->key_len = UBIFS_SK_LEN;
+ break;
+ default:
+ ubifs_err("unsupported key format");
+ err = -EINVAL;
+ goto out;
+ }
+
+ c->leb_cnt = le32_to_cpu(sup->leb_cnt);
+ c->max_leb_cnt = le32_to_cpu(sup->max_leb_cnt);
+ c->max_bud_bytes = le64_to_cpu(sup->max_bud_bytes);
+ c->log_lebs = le32_to_cpu(sup->log_lebs);
+ c->lpt_lebs = le32_to_cpu(sup->lpt_lebs);
+ c->orph_lebs = le32_to_cpu(sup->orph_lebs);
+ c->jhead_cnt = le32_to_cpu(sup->jhead_cnt) + NONDATA_JHEADS_CNT;
+ c->fanout = le32_to_cpu(sup->fanout);
+ c->lsave_cnt = le32_to_cpu(sup->lsave_cnt);
+ c->default_compr = le16_to_cpu(sup->default_compr);
+ c->rp_size = le64_to_cpu(sup->rp_size);
+ c->rp_uid = le32_to_cpu(sup->rp_uid);
+ c->rp_gid = le32_to_cpu(sup->rp_gid);
+ sup_flags = le32_to_cpu(sup->flags);
+
+ c->vfs_sb->s_time_gran = le32_to_cpu(sup->time_gran);
+ memcpy(&c->uuid, &sup->uuid, 16);
+ c->big_lpt = !!(sup_flags & UBIFS_FLG_BIGLPT);
+
+ /* Automatically increase file system size to the maximum size */
+ c->old_leb_cnt = c->leb_cnt;
+ if (c->leb_cnt < c->vi.size && c->leb_cnt < c->max_leb_cnt) {
+ c->leb_cnt = min_t(int, c->max_leb_cnt, c->vi.size);
+ dbg_mnt("Auto resizing (ro) from %d LEBs to %d LEBs",
+ c->old_leb_cnt, c->leb_cnt);
+ }
+
+ c->log_bytes = (long long)c->log_lebs * c->leb_size;
+ c->log_last = UBIFS_LOG_LNUM + c->log_lebs - 1;
+ c->lpt_first = UBIFS_LOG_LNUM + c->log_lebs;
+ c->lpt_last = c->lpt_first + c->lpt_lebs - 1;
+ c->orph_first = c->lpt_last + 1;
+ c->orph_last = c->orph_first + c->orph_lebs - 1;
+ c->main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS;
+ c->main_lebs -= c->log_lebs + c->lpt_lebs + c->orph_lebs;
+ c->main_first = c->leb_cnt - c->main_lebs;
+ c->report_rp_size = ubifs_reported_space(c, c->rp_size);
+
+ err = validate_sb(c, sup);
+out:
+ kfree(sup);
+ return err;
+}
diff --git a/fs/ubifs/scan.c b/fs/ubifs/scan.c
new file mode 100644
index 0000000..0ed8247
--- /dev/null
+++ b/fs/ubifs/scan.c
@@ -0,0 +1,362 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ * Artem Bityutskiy (Битюцкий Ðртём)
+ */
+
+/*
+ * This file implements the scan which is a general-purpose function for
+ * determining what nodes are in an eraseblock. The scan is used to replay the
+ * journal, to do garbage collection. for the TNC in-the-gaps method, and by
+ * debugging functions.
+ */
+
+#include "ubifs.h"
+
+/**
+ * scan_padding_bytes - scan for padding bytes.
+ * @buf: buffer to scan
+ * @len: length of buffer
+ *
+ * This function returns the number of padding bytes on success and
+ * %SCANNED_GARBAGE on failure.
+ */
+static int scan_padding_bytes(void *buf, int len)
+{
+ int pad_len = 0, max_pad_len = min_t(int, UBIFS_PAD_NODE_SZ, len);
+ uint8_t *p = buf;
+
+ dbg_scan("not a node");
+
+ while (pad_len < max_pad_len && *p++ == UBIFS_PADDING_BYTE)
+ pad_len += 1;
+
+ if (!pad_len || (pad_len & 7))
+ return SCANNED_GARBAGE;
+
+ dbg_scan("%d padding bytes", pad_len);
+
+ return pad_len;
+}
+
+/**
+ * ubifs_scan_a_node - scan for a node or padding.
+ * @c: UBIFS file-system description object
+ * @buf: buffer to scan
+ * @len: length of buffer
+ * @lnum: logical eraseblock number
+ * @offs: offset within the logical eraseblock
+ * @quiet: print no messages
+ *
+ * This function returns a scanning code to indicate what was scanned.
+ */
+int ubifs_scan_a_node(const struct ubifs_info *c, void *buf, int len, int lnum,
+ int offs, int quiet)
+{
+ struct ubifs_ch *ch = buf;
+ uint32_t magic;
+
+ magic = le32_to_cpu(ch->magic);
+
+ if (magic == 0xFFFFFFFF) {
+ dbg_scan("hit empty space");
+ return SCANNED_EMPTY_SPACE;
+ }
+
+ if (magic != UBIFS_NODE_MAGIC)
+ return scan_padding_bytes(buf, len);
+
+ if (len < UBIFS_CH_SZ)
+ return SCANNED_GARBAGE;
+
+ dbg_scan("scanning %s", dbg_ntype(ch->node_type));
+
+ if (ubifs_check_node(c, buf, lnum, offs, quiet, 1))
+ return SCANNED_A_CORRUPT_NODE;
+
+ if (ch->node_type == UBIFS_PAD_NODE) {
+ struct ubifs_pad_node *pad = buf;
+ int pad_len = le32_to_cpu(pad->pad_len);
+ int node_len = le32_to_cpu(ch->len);
+
+ /* Validate the padding node */
+ if (pad_len < 0 ||
+ offs + node_len + pad_len > c->leb_size) {
+ if (!quiet) {
+ ubifs_err("bad pad node at LEB %d:%d",
+ lnum, offs);
+ dbg_dump_node(c, pad);
+ }
+ return SCANNED_A_BAD_PAD_NODE;
+ }
+
+ /* Make the node pads to 8-byte boundary */
+ if ((node_len + pad_len) & 7) {
+ if (!quiet) {
+ dbg_err("bad padding length %d - %d",
+ offs, offs + node_len + pad_len);
+ }
+ return SCANNED_A_BAD_PAD_NODE;
+ }
+
+ dbg_scan("%d bytes padded, offset now %d",
+ pad_len, ALIGN(offs + node_len + pad_len, 8));
+
+ return node_len + pad_len;
+ }
+
+ return SCANNED_A_NODE;
+}
+
+/**
+ * ubifs_start_scan - create LEB scanning information at start of scan.
+ * @c: UBIFS file-system description object
+ * @lnum: logical eraseblock number
+ * @offs: offset to start at (usually zero)
+ * @sbuf: scan buffer (must be c->leb_size)
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+struct ubifs_scan_leb *ubifs_start_scan(const struct ubifs_info *c, int lnum,
+ int offs, void *sbuf)
+{
+ struct ubifs_scan_leb *sleb;
+ int err;
+
+ dbg_scan("scan LEB %d:%d", lnum, offs);
+
+ sleb = kzalloc(sizeof(struct ubifs_scan_leb), GFP_NOFS);
+ if (!sleb)
+ return ERR_PTR(-ENOMEM);
+
+ sleb->lnum = lnum;
+ INIT_LIST_HEAD(&sleb->nodes);
+ sleb->buf = sbuf;
+
+ err = ubi_read(c->ubi, lnum, sbuf + offs, offs, c->leb_size - offs);
+ if (err && err != -EBADMSG) {
+ ubifs_err("cannot read %d bytes from LEB %d:%d,"
+ " error %d", c->leb_size - offs, lnum, offs, err);
+ kfree(sleb);
+ return ERR_PTR(err);
+ }
+
+ if (err == -EBADMSG)
+ sleb->ecc = 1;
+
+ return sleb;
+}
+
+/**
+ * ubifs_end_scan - update LEB scanning information at end of scan.
+ * @c: UBIFS file-system description object
+ * @sleb: scanning information
+ * @lnum: logical eraseblock number
+ * @offs: offset to start at (usually zero)
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+void ubifs_end_scan(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
+ int lnum, int offs)
+{
+ lnum = lnum;
+ dbg_scan("stop scanning LEB %d at offset %d", lnum, offs);
+ ubifs_assert(offs % c->min_io_size == 0);
+
+ sleb->endpt = ALIGN(offs, c->min_io_size);
+}
+
+/**
+ * ubifs_add_snod - add a scanned node to LEB scanning information.
+ * @c: UBIFS file-system description object
+ * @sleb: scanning information
+ * @buf: buffer containing node
+ * @offs: offset of node on flash
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int ubifs_add_snod(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
+ void *buf, int offs)
+{
+ struct ubifs_ch *ch = buf;
+ struct ubifs_ino_node *ino = buf;
+ struct ubifs_scan_node *snod;
+
+ snod = kzalloc(sizeof(struct ubifs_scan_node), GFP_NOFS);
+ if (!snod)
+ return -ENOMEM;
+
+ snod->sqnum = le64_to_cpu(ch->sqnum);
+ snod->type = ch->node_type;
+ snod->offs = offs;
+ snod->len = le32_to_cpu(ch->len);
+ snod->node = buf;
+
+ switch (ch->node_type) {
+ case UBIFS_INO_NODE:
+ case UBIFS_DENT_NODE:
+ case UBIFS_XENT_NODE:
+ case UBIFS_DATA_NODE:
+ case UBIFS_TRUN_NODE:
+ /*
+ * The key is in the same place in all keyed
+ * nodes.
+ */
+ key_read(c, &ino->key, &snod->key);
+ break;
+ }
+ list_add_tail(&snod->list, &sleb->nodes);
+ sleb->nodes_cnt += 1;
+ return 0;
+}
+
+/**
+ * ubifs_scanned_corruption - print information after UBIFS scanned corruption.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number of corruption
+ * @offs: offset of corruption
+ * @buf: buffer containing corruption
+ */
+void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs,
+ void *buf)
+{
+ int len;
+
+ ubifs_err("corrupted data at LEB %d:%d", lnum, offs);
+ if (dbg_failure_mode)
+ return;
+ len = c->leb_size - offs;
+ if (len > 4096)
+ len = 4096;
+ dbg_err("first %d bytes from LEB %d:%d", len, lnum, offs);
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 4, buf, len, 1);
+}
+
+/**
+ * ubifs_scan - scan a logical eraseblock.
+ * @c: UBIFS file-system description object
+ * @lnum: logical eraseblock number
+ * @offs: offset to start at (usually zero)
+ * @sbuf: scan buffer (must be c->leb_size)
+ *
+ * This function scans LEB number @lnum and returns complete information about
+ * its contents. Returns an error code in case of failure.
+ */
+struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
+ int offs, void *sbuf)
+{
+ void *buf = sbuf + offs;
+ int err, len = c->leb_size - offs;
+ struct ubifs_scan_leb *sleb;
+
+ sleb = ubifs_start_scan(c, lnum, offs, sbuf);
+ if (IS_ERR(sleb))
+ return sleb;
+
+ while (len >= 8) {
+ struct ubifs_ch *ch = buf;
+ int node_len, ret;
+
+ dbg_scan("look at LEB %d:%d (%d bytes left)",
+ lnum, offs, len);
+
+ cond_resched();
+
+ ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 0);
+
+ if (ret > 0) {
+ /* Padding bytes or a valid padding node */
+ offs += ret;
+ buf += ret;
+ len -= ret;
+ continue;
+ }
+
+ if (ret == SCANNED_EMPTY_SPACE)
+ /* Empty space is checked later */
+ break;
+
+ switch (ret) {
+ case SCANNED_GARBAGE:
+ dbg_err("garbage");
+ goto corrupted;
+ case SCANNED_A_NODE:
+ break;
+ case SCANNED_A_CORRUPT_NODE:
+ case SCANNED_A_BAD_PAD_NODE:
+ dbg_err("bad node");
+ goto corrupted;
+ default:
+ dbg_err("unknown");
+ goto corrupted;
+ }
+
+ err = ubifs_add_snod(c, sleb, buf, offs);
+ if (err)
+ goto error;
+
+ node_len = ALIGN(le32_to_cpu(ch->len), 8);
+ offs += node_len;
+ buf += node_len;
+ len -= node_len;
+ }
+
+ if (offs % c->min_io_size)
+ goto corrupted;
+
+ ubifs_end_scan(c, sleb, lnum, offs);
+
+ for (; len > 4; offs += 4, buf = buf + 4, len -= 4)
+ if (*(uint32_t *)buf != 0xffffffff)
+ break;
+ for (; len; offs++, buf++, len--)
+ if (*(uint8_t *)buf != 0xff) {
+ ubifs_err("corrupt empty space at LEB %d:%d",
+ lnum, offs);
+ goto corrupted;
+ }
+
+ return sleb;
+
+corrupted:
+ ubifs_scanned_corruption(c, lnum, offs, buf);
+ err = -EUCLEAN;
+error:
+ ubifs_err("LEB %d scanning failed", lnum);
+ ubifs_scan_destroy(sleb);
+ return ERR_PTR(err);
+}
+
+/**
+ * ubifs_scan_destroy - destroy LEB scanning information.
+ * @sleb: scanning information to free
+ */
+void ubifs_scan_destroy(struct ubifs_scan_leb *sleb)
+{
+ struct ubifs_scan_node *node;
+ struct list_head *head;
+
+ head = &sleb->nodes;
+ while (!list_empty(head)) {
+ node = list_entry(head->next, struct ubifs_scan_node, list);
+ list_del(&node->list);
+ kfree(node);
+ }
+ kfree(sleb);
+}
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
new file mode 100644
index 0000000..95f2a41
--- /dev/null
+++ b/fs/ubifs/super.c
@@ -0,0 +1,1189 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Ðртём)
+ * Adrian Hunter
+ */
+
+/*
+ * This file implements UBIFS initialization and VFS superblock operations. Some
+ * initialization stuff which is rather large and complex is placed at
+ * corresponding subsystems, but most of it is here.
+ */
+
+#include "ubifs.h"
+#include <linux/math64.h>
+
+#define INODE_LOCKED_MAX 64
+
+struct super_block *ubifs_sb;
+static struct inode *inodes_locked_down[INODE_LOCKED_MAX];
+
+/* shrinker.c */
+
+/* List of all UBIFS file-system instances */
+struct list_head ubifs_infos;
+
+/* linux/fs/super.c */
+
+static int sb_set(struct super_block *sb, void *data)
+{
+ dev_t *dev = data;
+
+ sb->s_dev = *dev;
+ return 0;
+}
+
+/**
+ * sget - find or create a superblock
+ * @type: filesystem type superblock should belong to
+ * @test: comparison callback
+ * @set: setup callback
+ * @data: argument to each of them
+ */
+struct super_block *sget(struct file_system_type *type,
+ int (*test)(struct super_block *,void *),
+ int (*set)(struct super_block *,void *),
+ void *data)
+{
+ struct super_block *s = NULL;
+ int err;
+
+ s = kzalloc(sizeof(struct super_block), GFP_USER);
+ if (!s) {
+ err = -ENOMEM;
+ return ERR_PTR(err);
+ }
+
+ INIT_LIST_HEAD(&s->s_instances);
+ INIT_LIST_HEAD(&s->s_inodes);
+ s->s_time_gran = 1000000000;
+
+ err = set(s, data);
+ if (err) {
+ return ERR_PTR(err);
+ }
+ s->s_type = type;
+ strncpy(s->s_id, type->name, sizeof(s->s_id));
+ list_add(&s->s_instances, &type->fs_supers);
+ return s;
+}
+
+/**
+ * validate_inode - validate inode.
+ * @c: UBIFS file-system description object
+ * @inode: the inode to validate
+ *
+ * This is a helper function for 'ubifs_iget()' which validates various fields
+ * of a newly built inode to make sure they contain sane values and prevent
+ * possible vulnerabilities. Returns zero if the inode is all right and
+ * a non-zero error code if not.
+ */
+static int validate_inode(struct ubifs_info *c, const struct inode *inode)
+{
+ int err;
+ const struct ubifs_inode *ui = ubifs_inode(inode);
+
+ if (inode->i_size > c->max_inode_sz) {
+ ubifs_err("inode is too large (%lld)",
+ (long long)inode->i_size);
+ return 1;
+ }
+
+ if (ui->compr_type < 0 || ui->compr_type >= UBIFS_COMPR_TYPES_CNT) {
+ ubifs_err("unknown compression type %d", ui->compr_type);
+ return 2;
+ }
+
+ if (ui->data_len < 0 || ui->data_len > UBIFS_MAX_INO_DATA)
+ return 4;
+
+ if (!ubifs_compr_present(ui->compr_type)) {
+ ubifs_warn("inode %lu uses '%s' compression, but it was not "
+ "compiled in", inode->i_ino,
+ ubifs_compr_name(ui->compr_type));
+ }
+
+ err = dbg_check_dir_size(c, inode);
+ return err;
+}
+
+struct inode *iget_locked(struct super_block *sb, unsigned long ino)
+{
+ struct inode *inode;
+
+ inode = (struct inode *)malloc(sizeof(struct ubifs_inode));
+ if (inode) {
+ inode->i_ino = ino;
+ inode->i_sb = sb;
+ list_add(&inode->i_sb_list, &sb->s_inodes);
+ inode->i_state = I_LOCK | I_NEW;
+ }
+
+ return inode;
+}
+
+int ubifs_iput(struct inode *inode)
+{
+ list_del_init(&inode->i_sb_list);
+
+ free(inode);
+ return 0;
+}
+
+/*
+ * Lock (save) inode in inode array for readback after recovery
+ */
+void iput(struct inode *inode)
+{
+ int i;
+ struct inode *ino;
+
+ /*
+ * Search end of list
+ */
+ for (i = 0; i < INODE_LOCKED_MAX; i++) {
+ if (inodes_locked_down[i] == NULL)
+ break;
+ }
+
+ if (i >= INODE_LOCKED_MAX) {
+ ubifs_err("Error, can't lock (save) more inodes while recovery!!!");
+ return;
+ }
+
+ /*
+ * Allocate and use new inode
+ */
+ ino = (struct inode *)malloc(sizeof(struct ubifs_inode));
+ memcpy(ino, inode, sizeof(struct ubifs_inode));
+
+ /*
+ * Finally save inode in array
+ */
+ inodes_locked_down[i] = ino;
+}
+
+struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
+{
+ int err;
+ union ubifs_key key;
+ struct ubifs_ino_node *ino;
+ struct ubifs_info *c = sb->s_fs_info;
+ struct inode *inode;
+ struct ubifs_inode *ui;
+ int i;
+
+ dbg_gen("inode %lu", inum);
+
+ /*
+ * U-Boot special handling of locked down inodes via recovery
+ * e.g. ubifs_recover_size()
+ */
+ for (i = 0; i < INODE_LOCKED_MAX; i++) {
+ /*
+ * Exit on last entry (NULL), inode not found in list
+ */
+ if (inodes_locked_down[i] == NULL)
+ break;
+
+ if (inodes_locked_down[i]->i_ino == inum) {
+ /*
+ * We found the locked down inode in our array,
+ * so just return this pointer instead of creating
+ * a new one.
+ */
+ return inodes_locked_down[i];
+ }
+ }
+
+ inode = iget_locked(sb, inum);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ if (!(inode->i_state & I_NEW))
+ return inode;
+ ui = ubifs_inode(inode);
+
+ ino = kmalloc(UBIFS_MAX_INO_NODE_SZ, GFP_NOFS);
+ if (!ino) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ ino_key_init(c, &key, inode->i_ino);
+
+ err = ubifs_tnc_lookup(c, &key, ino);
+ if (err)
+ goto out_ino;
+
+ inode->i_flags |= (S_NOCMTIME | S_NOATIME);
+ inode->i_nlink = le32_to_cpu(ino->nlink);
+ inode->i_uid = le32_to_cpu(ino->uid);
+ inode->i_gid = le32_to_cpu(ino->gid);
+ inode->i_atime.tv_sec = (int64_t)le64_to_cpu(ino->atime_sec);
+ inode->i_atime.tv_nsec = le32_to_cpu(ino->atime_nsec);
+ inode->i_mtime.tv_sec = (int64_t)le64_to_cpu(ino->mtime_sec);
+ inode->i_mtime.tv_nsec = le32_to_cpu(ino->mtime_nsec);
+ inode->i_ctime.tv_sec = (int64_t)le64_to_cpu(ino->ctime_sec);
+ inode->i_ctime.tv_nsec = le32_to_cpu(ino->ctime_nsec);
+ inode->i_mode = le32_to_cpu(ino->mode);
+ inode->i_size = le64_to_cpu(ino->size);
+
+ ui->data_len = le32_to_cpu(ino->data_len);
+ ui->flags = le32_to_cpu(ino->flags);
+ ui->compr_type = le16_to_cpu(ino->compr_type);
+ ui->creat_sqnum = le64_to_cpu(ino->creat_sqnum);
+ ui->synced_i_size = ui->ui_size = inode->i_size;
+
+ err = validate_inode(c, inode);
+ if (err)
+ goto out_invalid;
+
+ if ((inode->i_mode & S_IFMT) == S_IFLNK) {
+ if (ui->data_len <= 0 || ui->data_len > UBIFS_MAX_INO_DATA) {
+ err = 12;
+ goto out_invalid;
+ }
+ ui->data = kmalloc(ui->data_len + 1, GFP_NOFS);
+ if (!ui->data) {
+ err = -ENOMEM;
+ goto out_ino;
+ }
+ memcpy(ui->data, ino->data, ui->data_len);
+ ((char *)ui->data)[ui->data_len] = '\0';
+ }
+
+ kfree(ino);
+ inode->i_state &= ~(I_LOCK | I_NEW);
+ return inode;
+
+out_invalid:
+ ubifs_err("inode %lu validation failed, error %d", inode->i_ino, err);
+ dbg_dump_node(c, ino);
+ dbg_dump_inode(c, inode);
+ err = -EINVAL;
+out_ino:
+ kfree(ino);
+out:
+ ubifs_err("failed to read inode %lu, error %d", inode->i_ino, err);
+ return ERR_PTR(err);
+}
+
+/**
+ * init_constants_early - initialize UBIFS constants.
+ * @c: UBIFS file-system description object
+ *
+ * This function initialize UBIFS constants which do not need the superblock to
+ * be read. It also checks that the UBI volume satisfies basic UBIFS
+ * requirements. Returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int init_constants_early(struct ubifs_info *c)
+{
+ if (c->vi.corrupted) {
+ ubifs_warn("UBI volume is corrupted - read-only mode");
+ c->ro_media = 1;
+ }
+
+ if (c->di.ro_mode) {
+ ubifs_msg("read-only UBI device");
+ c->ro_media = 1;
+ }
+
+ if (c->vi.vol_type == UBI_STATIC_VOLUME) {
+ ubifs_msg("static UBI volume - read-only mode");
+ c->ro_media = 1;
+ }
+
+ c->leb_cnt = c->vi.size;
+ c->leb_size = c->vi.usable_leb_size;
+ c->half_leb_size = c->leb_size / 2;
+ c->min_io_size = c->di.min_io_size;
+ c->min_io_shift = fls(c->min_io_size) - 1;
+
+ if (c->leb_size < UBIFS_MIN_LEB_SZ) {
+ ubifs_err("too small LEBs (%d bytes), min. is %d bytes",
+ c->leb_size, UBIFS_MIN_LEB_SZ);
+ return -EINVAL;
+ }
+
+ if (c->leb_cnt < UBIFS_MIN_LEB_CNT) {
+ ubifs_err("too few LEBs (%d), min. is %d",
+ c->leb_cnt, UBIFS_MIN_LEB_CNT);
+ return -EINVAL;
+ }
+
+ if (!is_power_of_2(c->min_io_size)) {
+ ubifs_err("bad min. I/O size %d", c->min_io_size);
+ return -EINVAL;
+ }
+
+ /*
+ * UBIFS aligns all node to 8-byte boundary, so to make function in
+ * io.c simpler, assume minimum I/O unit size to be 8 bytes if it is
+ * less than 8.
+ */
+ if (c->min_io_size < 8) {
+ c->min_io_size = 8;
+ c->min_io_shift = 3;
+ }
+
+ c->ref_node_alsz = ALIGN(UBIFS_REF_NODE_SZ, c->min_io_size);
+ c->mst_node_alsz = ALIGN(UBIFS_MST_NODE_SZ, c->min_io_size);
+
+ /*
+ * Initialize node length ranges which are mostly needed for node
+ * length validation.
+ */
+ c->ranges[UBIFS_PAD_NODE].len = UBIFS_PAD_NODE_SZ;
+ c->ranges[UBIFS_SB_NODE].len = UBIFS_SB_NODE_SZ;
+ c->ranges[UBIFS_MST_NODE].len = UBIFS_MST_NODE_SZ;
+ c->ranges[UBIFS_REF_NODE].len = UBIFS_REF_NODE_SZ;
+ c->ranges[UBIFS_TRUN_NODE].len = UBIFS_TRUN_NODE_SZ;
+ c->ranges[UBIFS_CS_NODE].len = UBIFS_CS_NODE_SZ;
+
+ c->ranges[UBIFS_INO_NODE].min_len = UBIFS_INO_NODE_SZ;
+ c->ranges[UBIFS_INO_NODE].max_len = UBIFS_MAX_INO_NODE_SZ;
+ c->ranges[UBIFS_ORPH_NODE].min_len =
+ UBIFS_ORPH_NODE_SZ + sizeof(__le64);
+ c->ranges[UBIFS_ORPH_NODE].max_len = c->leb_size;
+ c->ranges[UBIFS_DENT_NODE].min_len = UBIFS_DENT_NODE_SZ;
+ c->ranges[UBIFS_DENT_NODE].max_len = UBIFS_MAX_DENT_NODE_SZ;
+ c->ranges[UBIFS_XENT_NODE].min_len = UBIFS_XENT_NODE_SZ;
+ c->ranges[UBIFS_XENT_NODE].max_len = UBIFS_MAX_XENT_NODE_SZ;
+ c->ranges[UBIFS_DATA_NODE].min_len = UBIFS_DATA_NODE_SZ;
+ c->ranges[UBIFS_DATA_NODE].max_len = UBIFS_MAX_DATA_NODE_SZ;
+ /*
+ * Minimum indexing node size is amended later when superblock is
+ * read and the key length is known.
+ */
+ c->ranges[UBIFS_IDX_NODE].min_len = UBIFS_IDX_NODE_SZ + UBIFS_BRANCH_SZ;
+ /*
+ * Maximum indexing node size is amended later when superblock is
+ * read and the fanout is known.
+ */
+ c->ranges[UBIFS_IDX_NODE].max_len = INT_MAX;
+
+ /*
+ * Initialize dead and dark LEB space watermarks. See gc.c for comments
+ * about these values.
+ */
+ c->dead_wm = ALIGN(MIN_WRITE_SZ, c->min_io_size);
+ c->dark_wm = ALIGN(UBIFS_MAX_NODE_SZ, c->min_io_size);
+
+ /*
+ * Calculate how many bytes would be wasted at the end of LEB if it was
+ * fully filled with data nodes of maximum size. This is used in
+ * calculations when reporting free space.
+ */
+ c->leb_overhead = c->leb_size % UBIFS_MAX_DATA_NODE_SZ;
+
+ return 0;
+}
+
+/*
+ * init_constants_sb - initialize UBIFS constants.
+ * @c: UBIFS file-system description object
+ *
+ * This is a helper function which initializes various UBIFS constants after
+ * the superblock has been read. It also checks various UBIFS parameters and
+ * makes sure they are all right. Returns zero in case of success and a
+ * negative error code in case of failure.
+ */
+static int init_constants_sb(struct ubifs_info *c)
+{
+ int tmp, err;
+ long long tmp64;
+
+ c->main_bytes = (long long)c->main_lebs * c->leb_size;
+ c->max_znode_sz = sizeof(struct ubifs_znode) +
+ c->fanout * sizeof(struct ubifs_zbranch);
+
+ tmp = ubifs_idx_node_sz(c, 1);
+ c->ranges[UBIFS_IDX_NODE].min_len = tmp;
+ c->min_idx_node_sz = ALIGN(tmp, 8);
+
+ tmp = ubifs_idx_node_sz(c, c->fanout);
+ c->ranges[UBIFS_IDX_NODE].max_len = tmp;
+ c->max_idx_node_sz = ALIGN(tmp, 8);
+
+ /* Make sure LEB size is large enough to fit full commit */
+ tmp = UBIFS_CS_NODE_SZ + UBIFS_REF_NODE_SZ * c->jhead_cnt;
+ tmp = ALIGN(tmp, c->min_io_size);
+ if (tmp > c->leb_size) {
+ dbg_err("too small LEB size %d, at least %d needed",
+ c->leb_size, tmp);
+ return -EINVAL;
+ }
+
+ /*
+ * Make sure that the log is large enough to fit reference nodes for
+ * all buds plus one reserved LEB.
+ */
+ tmp64 = c->max_bud_bytes + c->leb_size - 1;
+ c->max_bud_cnt = div_u64(tmp64, c->leb_size);
+ tmp = (c->ref_node_alsz * c->max_bud_cnt + c->leb_size - 1);
+ tmp /= c->leb_size;
+ tmp += 1;
+ if (c->log_lebs < tmp) {
+ dbg_err("too small log %d LEBs, required min. %d LEBs",
+ c->log_lebs, tmp);
+ return -EINVAL;
+ }
+
+ /*
+ * When budgeting we assume worst-case scenarios when the pages are not
+ * be compressed and direntries are of the maximum size.
+ *
+ * Note, data, which may be stored in inodes is budgeted separately, so
+ * it is not included into 'c->inode_budget'.
+ */
+ c->page_budget = UBIFS_MAX_DATA_NODE_SZ * UBIFS_BLOCKS_PER_PAGE;
+ c->inode_budget = UBIFS_INO_NODE_SZ;
+ c->dent_budget = UBIFS_MAX_DENT_NODE_SZ;
+
+ /*
+ * When the amount of flash space used by buds becomes
+ * 'c->max_bud_bytes', UBIFS just blocks all writers and starts commit.
+ * The writers are unblocked when the commit is finished. To avoid
+ * writers to be blocked UBIFS initiates background commit in advance,
+ * when number of bud bytes becomes above the limit defined below.
+ */
+ c->bg_bud_bytes = (c->max_bud_bytes * 13) >> 4;
+
+ /*
+ * Ensure minimum journal size. All the bytes in the journal heads are
+ * considered to be used, when calculating the current journal usage.
+ * Consequently, if the journal is too small, UBIFS will treat it as
+ * always full.
+ */
+ tmp64 = (long long)(c->jhead_cnt + 1) * c->leb_size + 1;
+ if (c->bg_bud_bytes < tmp64)
+ c->bg_bud_bytes = tmp64;
+ if (c->max_bud_bytes < tmp64 + c->leb_size)
+ c->max_bud_bytes = tmp64 + c->leb_size;
+
+ err = ubifs_calc_lpt_geom(c);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+/*
+ * init_constants_master - initialize UBIFS constants.
+ * @c: UBIFS file-system description object
+ *
+ * This is a helper function which initializes various UBIFS constants after
+ * the master node has been read. It also checks various UBIFS parameters and
+ * makes sure they are all right.
+ */
+static void init_constants_master(struct ubifs_info *c)
+{
+ long long tmp64;
+
+ c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+
+ /*
+ * Calculate total amount of FS blocks. This number is not used
+ * internally because it does not make much sense for UBIFS, but it is
+ * necessary to report something for the 'statfs()' call.
+ *
+ * Subtract the LEB reserved for GC, the LEB which is reserved for
+ * deletions, minimum LEBs for the index, and assume only one journal
+ * head is available.
+ */
+ tmp64 = c->main_lebs - 1 - 1 - MIN_INDEX_LEBS - c->jhead_cnt + 1;
+ tmp64 *= (long long)c->leb_size - c->leb_overhead;
+ tmp64 = ubifs_reported_space(c, tmp64);
+ c->block_cnt = tmp64 >> UBIFS_BLOCK_SHIFT;
+}
+
+/**
+ * free_orphans - free orphans.
+ * @c: UBIFS file-system description object
+ */
+static void free_orphans(struct ubifs_info *c)
+{
+ struct ubifs_orphan *orph;
+
+ while (c->orph_dnext) {
+ orph = c->orph_dnext;
+ c->orph_dnext = orph->dnext;
+ list_del(&orph->list);
+ kfree(orph);
+ }
+
+ while (!list_empty(&c->orph_list)) {
+ orph = list_entry(c->orph_list.next, struct ubifs_orphan, list);
+ list_del(&orph->list);
+ kfree(orph);
+ dbg_err("orphan list not empty at unmount");
+ }
+
+ vfree(c->orph_buf);
+ c->orph_buf = NULL;
+}
+
+/**
+ * check_volume_empty - check if the UBI volume is empty.
+ * @c: UBIFS file-system description object
+ *
+ * This function checks if the UBIFS volume is empty by looking if its LEBs are
+ * mapped or not. The result of checking is stored in the @c->empty variable.
+ * Returns zero in case of success and a negative error code in case of
+ * failure.
+ */
+static int check_volume_empty(struct ubifs_info *c)
+{
+ int lnum, err;
+
+ c->empty = 1;
+ for (lnum = 0; lnum < c->leb_cnt; lnum++) {
+ err = ubi_is_mapped(c->ubi, lnum);
+ if (unlikely(err < 0))
+ return err;
+ if (err == 1) {
+ c->empty = 0;
+ break;
+ }
+
+ cond_resched();
+ }
+
+ return 0;
+}
+
+/**
+ * mount_ubifs - mount UBIFS file-system.
+ * @c: UBIFS file-system description object
+ *
+ * This function mounts UBIFS file system. Returns zero in case of success and
+ * a negative error code in case of failure.
+ *
+ * Note, the function does not de-allocate resources it it fails half way
+ * through, and the caller has to do this instead.
+ */
+static int mount_ubifs(struct ubifs_info *c)
+{
+ struct super_block *sb = c->vfs_sb;
+ int err, mounted_read_only = (sb->s_flags & MS_RDONLY);
+ long long x;
+ size_t sz;
+
+ err = init_constants_early(c);
+ if (err)
+ return err;
+
+ err = ubifs_debugging_init(c);
+ if (err)
+ return err;
+
+ err = check_volume_empty(c);
+ if (err)
+ goto out_free;
+
+ if (c->empty && (mounted_read_only || c->ro_media)) {
+ /*
+ * This UBI volume is empty, and read-only, or the file system
+ * is mounted read-only - we cannot format it.
+ */
+ ubifs_err("can't format empty UBI volume: read-only %s",
+ c->ro_media ? "UBI volume" : "mount");
+ err = -EROFS;
+ goto out_free;
+ }
+
+ if (c->ro_media && !mounted_read_only) {
+ ubifs_err("cannot mount read-write - read-only media");
+ err = -EROFS;
+ goto out_free;
+ }
+
+ /*
+ * The requirement for the buffer is that it should fit indexing B-tree
+ * height amount of integers. We assume the height if the TNC tree will
+ * never exceed 64.
+ */
+ err = -ENOMEM;
+ c->bottom_up_buf = kmalloc(BOTTOM_UP_HEIGHT * sizeof(int), GFP_KERNEL);
+ if (!c->bottom_up_buf)
+ goto out_free;
+
+ c->sbuf = vmalloc(c->leb_size);
+ if (!c->sbuf)
+ goto out_free;
+
+ /*
+ * We have to check all CRCs, even for data nodes, when we mount the FS
+ * (specifically, when we are replaying).
+ */
+ c->always_chk_crc = 1;
+
+ err = ubifs_read_superblock(c);
+ if (err)
+ goto out_free;
+
+ /*
+ * Make sure the compressor which is set as default in the superblock
+ * or overridden by mount options is actually compiled in.
+ */
+ if (!ubifs_compr_present(c->default_compr)) {
+ ubifs_err("'compressor \"%s\" is not compiled in",
+ ubifs_compr_name(c->default_compr));
+ goto out_free;
+ }
+
+ dbg_failure_mode_registration(c);
+
+ err = init_constants_sb(c);
+ if (err)
+ goto out_free;
+
+ sz = ALIGN(c->max_idx_node_sz, c->min_io_size);
+ sz = ALIGN(sz + c->max_idx_node_sz, c->min_io_size);
+ c->cbuf = kmalloc(sz, GFP_NOFS);
+ if (!c->cbuf) {
+ err = -ENOMEM;
+ goto out_free;
+ }
+
+ sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, c->vi.vol_id);
+
+ err = ubifs_read_master(c);
+ if (err)
+ goto out_master;
+
+ init_constants_master(c);
+
+ if ((c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY)) != 0) {
+ ubifs_msg("recovery needed");
+ c->need_recovery = 1;
+ }
+
+ err = ubifs_lpt_init(c, 1, !mounted_read_only);
+ if (err)
+ goto out_lpt;
+
+ err = dbg_check_idx_size(c, c->old_idx_sz);
+ if (err)
+ goto out_lpt;
+
+ err = ubifs_replay_journal(c);
+ if (err)
+ goto out_journal;
+
+ err = ubifs_mount_orphans(c, c->need_recovery, mounted_read_only);
+ if (err)
+ goto out_orphans;
+
+ if (c->need_recovery) {
+ err = ubifs_recover_size(c);
+ if (err)
+ goto out_orphans;
+ }
+
+ spin_lock(&ubifs_infos_lock);
+ list_add_tail(&c->infos_list, &ubifs_infos);
+ spin_unlock(&ubifs_infos_lock);
+
+ if (c->need_recovery) {
+ if (mounted_read_only)
+ ubifs_msg("recovery deferred");
+ else {
+ c->need_recovery = 0;
+ ubifs_msg("recovery completed");
+ }
+ }
+
+ err = dbg_check_filesystem(c);
+ if (err)
+ goto out_infos;
+
+ c->always_chk_crc = 0;
+
+ ubifs_msg("mounted UBI device %d, volume %d, name \"%s\"",
+ c->vi.ubi_num, c->vi.vol_id, c->vi.name);
+ if (mounted_read_only)
+ ubifs_msg("mounted read-only");
+ x = (long long)c->main_lebs * c->leb_size;
+ ubifs_msg("file system size: %lld bytes (%lld KiB, %lld MiB, %d "
+ "LEBs)", x, x >> 10, x >> 20, c->main_lebs);
+ x = (long long)c->log_lebs * c->leb_size + c->max_bud_bytes;
+ ubifs_msg("journal size: %lld bytes (%lld KiB, %lld MiB, %d "
+ "LEBs)", x, x >> 10, x >> 20, c->log_lebs + c->max_bud_cnt);
+ ubifs_msg("media format: %d (latest is %d)",
+ c->fmt_version, UBIFS_FORMAT_VERSION);
+ ubifs_msg("default compressor: %s", ubifs_compr_name(c->default_compr));
+ ubifs_msg("reserved for root: %llu bytes (%llu KiB)",
+ c->report_rp_size, c->report_rp_size >> 10);
+
+ dbg_msg("compiled on: " __DATE__ " at " __TIME__);
+ dbg_msg("min. I/O unit size: %d bytes", c->min_io_size);
+ dbg_msg("LEB size: %d bytes (%d KiB)",
+ c->leb_size, c->leb_size >> 10);
+ dbg_msg("data journal heads: %d",
+ c->jhead_cnt - NONDATA_JHEADS_CNT);
+ dbg_msg("UUID: %02X%02X%02X%02X-%02X%02X"
+ "-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
+ c->uuid[0], c->uuid[1], c->uuid[2], c->uuid[3],
+ c->uuid[4], c->uuid[5], c->uuid[6], c->uuid[7],
+ c->uuid[8], c->uuid[9], c->uuid[10], c->uuid[11],
+ c->uuid[12], c->uuid[13], c->uuid[14], c->uuid[15]);
+ dbg_msg("big_lpt %d", c->big_lpt);
+ dbg_msg("log LEBs: %d (%d - %d)",
+ c->log_lebs, UBIFS_LOG_LNUM, c->log_last);
+ dbg_msg("LPT area LEBs: %d (%d - %d)",
+ c->lpt_lebs, c->lpt_first, c->lpt_last);
+ dbg_msg("orphan area LEBs: %d (%d - %d)",
+ c->orph_lebs, c->orph_first, c->orph_last);
+ dbg_msg("main area LEBs: %d (%d - %d)",
+ c->main_lebs, c->main_first, c->leb_cnt - 1);
+ dbg_msg("index LEBs: %d", c->lst.idx_lebs);
+ dbg_msg("total index bytes: %lld (%lld KiB, %lld MiB)",
+ c->old_idx_sz, c->old_idx_sz >> 10, c->old_idx_sz >> 20);
+ dbg_msg("key hash type: %d", c->key_hash_type);
+ dbg_msg("tree fanout: %d", c->fanout);
+ dbg_msg("reserved GC LEB: %d", c->gc_lnum);
+ dbg_msg("first main LEB: %d", c->main_first);
+ dbg_msg("max. znode size %d", c->max_znode_sz);
+ dbg_msg("max. index node size %d", c->max_idx_node_sz);
+ dbg_msg("node sizes: data %zu, inode %zu, dentry %zu",
+ UBIFS_DATA_NODE_SZ, UBIFS_INO_NODE_SZ, UBIFS_DENT_NODE_SZ);
+ dbg_msg("node sizes: trun %zu, sb %zu, master %zu",
+ UBIFS_TRUN_NODE_SZ, UBIFS_SB_NODE_SZ, UBIFS_MST_NODE_SZ);
+ dbg_msg("node sizes: ref %zu, cmt. start %zu, orph %zu",
+ UBIFS_REF_NODE_SZ, UBIFS_CS_NODE_SZ, UBIFS_ORPH_NODE_SZ);
+ dbg_msg("max. node sizes: data %zu, inode %zu dentry %zu",
+ UBIFS_MAX_DATA_NODE_SZ, UBIFS_MAX_INO_NODE_SZ,
+ UBIFS_MAX_DENT_NODE_SZ);
+ dbg_msg("dead watermark: %d", c->dead_wm);
+ dbg_msg("dark watermark: %d", c->dark_wm);
+ dbg_msg("LEB overhead: %d", c->leb_overhead);
+ x = (long long)c->main_lebs * c->dark_wm;
+ dbg_msg("max. dark space: %lld (%lld KiB, %lld MiB)",
+ x, x >> 10, x >> 20);
+ dbg_msg("maximum bud bytes: %lld (%lld KiB, %lld MiB)",
+ c->max_bud_bytes, c->max_bud_bytes >> 10,
+ c->max_bud_bytes >> 20);
+ dbg_msg("BG commit bud bytes: %lld (%lld KiB, %lld MiB)",
+ c->bg_bud_bytes, c->bg_bud_bytes >> 10,
+ c->bg_bud_bytes >> 20);
+ dbg_msg("current bud bytes %lld (%lld KiB, %lld MiB)",
+ c->bud_bytes, c->bud_bytes >> 10, c->bud_bytes >> 20);
+ dbg_msg("max. seq. number: %llu", c->max_sqnum);
+ dbg_msg("commit number: %llu", c->cmt_no);
+
+ return 0;
+
+out_infos:
+ spin_lock(&ubifs_infos_lock);
+ list_del(&c->infos_list);
+ spin_unlock(&ubifs_infos_lock);
+out_orphans:
+ free_orphans(c);
+out_journal:
+out_lpt:
+ ubifs_lpt_free(c, 0);
+out_master:
+ kfree(c->mst_node);
+ kfree(c->rcvrd_mst_node);
+ if (c->bgt)
+ kthread_stop(c->bgt);
+ kfree(c->cbuf);
+out_free:
+ vfree(c->ileb_buf);
+ vfree(c->sbuf);
+ kfree(c->bottom_up_buf);
+ ubifs_debugging_exit(c);
+ return err;
+}
+
+/**
+ * ubifs_umount - un-mount UBIFS file-system.
+ * @c: UBIFS file-system description object
+ *
+ * Note, this function is called to free allocated resourced when un-mounting,
+ * as well as free resources when an error occurred while we were half way
+ * through mounting (error path cleanup function). So it has to make sure the
+ * resource was actually allocated before freeing it.
+ */
+static void ubifs_umount(struct ubifs_info *c)
+{
+ dbg_gen("un-mounting UBI device %d, volume %d", c->vi.ubi_num,
+ c->vi.vol_id);
+
+ spin_lock(&ubifs_infos_lock);
+ list_del(&c->infos_list);
+ spin_unlock(&ubifs_infos_lock);
+
+ if (c->bgt)
+ kthread_stop(c->bgt);
+
+ free_orphans(c);
+ ubifs_lpt_free(c, 0);
+
+ kfree(c->cbuf);
+ kfree(c->rcvrd_mst_node);
+ kfree(c->mst_node);
+ vfree(c->ileb_buf);
+ vfree(c->sbuf);
+ kfree(c->bottom_up_buf);
+ ubifs_debugging_exit(c);
+
+ /* Finally free U-Boot's global copy of superblock */
+ free(ubifs_sb->s_fs_info);
+ free(ubifs_sb);
+}
+
+/**
+ * open_ubi - parse UBI device name string and open the UBI device.
+ * @name: UBI volume name
+ * @mode: UBI volume open mode
+ *
+ * There are several ways to specify UBI volumes when mounting UBIFS:
+ * o ubiX_Y - UBI device number X, volume Y;
+ * o ubiY - UBI device number 0, volume Y;
+ * o ubiX:NAME - mount UBI device X, volume with name NAME;
+ * o ubi:NAME - mount UBI device 0, volume with name NAME.
+ *
+ * Alternative '!' separator may be used instead of ':' (because some shells
+ * like busybox may interpret ':' as an NFS host name separator). This function
+ * returns ubi volume object in case of success and a negative error code in
+ * case of failure.
+ */
+static struct ubi_volume_desc *open_ubi(const char *name, int mode)
+{
+ int dev, vol;
+ char *endptr;
+
+ if (name[0] != 'u' || name[1] != 'b' || name[2] != 'i')
+ return ERR_PTR(-EINVAL);
+
+ /* ubi:NAME method */
+ if ((name[3] == ':' || name[3] == '!') && name[4] != '\0')
+ return ubi_open_volume_nm(0, name + 4, mode);
+
+ if (!isdigit(name[3]))
+ return ERR_PTR(-EINVAL);
+
+ dev = simple_strtoul(name + 3, &endptr, 0);
+
+ /* ubiY method */
+ if (*endptr == '\0')
+ return ubi_open_volume(0, dev, mode);
+
+ /* ubiX_Y method */
+ if (*endptr == '_' && isdigit(endptr[1])) {
+ vol = simple_strtoul(endptr + 1, &endptr, 0);
+ if (*endptr != '\0')
+ return ERR_PTR(-EINVAL);
+ return ubi_open_volume(dev, vol, mode);
+ }
+
+ /* ubiX:NAME method */
+ if ((*endptr == ':' || *endptr == '!') && endptr[1] != '\0')
+ return ubi_open_volume_nm(dev, ++endptr, mode);
+
+ return ERR_PTR(-EINVAL);
+}
+
+static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
+{
+ struct ubi_volume_desc *ubi = sb->s_fs_info;
+ struct ubifs_info *c;
+ struct inode *root;
+ int err;
+
+ c = kzalloc(sizeof(struct ubifs_info), GFP_KERNEL);
+ if (!c)
+ return -ENOMEM;
+
+ spin_lock_init(&c->cnt_lock);
+ spin_lock_init(&c->cs_lock);
+ spin_lock_init(&c->buds_lock);
+ spin_lock_init(&c->space_lock);
+ spin_lock_init(&c->orphan_lock);
+ init_rwsem(&c->commit_sem);
+ mutex_init(&c->lp_mutex);
+ mutex_init(&c->tnc_mutex);
+ mutex_init(&c->log_mutex);
+ mutex_init(&c->mst_mutex);
+ mutex_init(&c->umount_mutex);
+ init_waitqueue_head(&c->cmt_wq);
+ c->buds = RB_ROOT;
+ c->old_idx = RB_ROOT;
+ c->size_tree = RB_ROOT;
+ c->orph_tree = RB_ROOT;
+ INIT_LIST_HEAD(&c->infos_list);
+ INIT_LIST_HEAD(&c->idx_gc);
+ INIT_LIST_HEAD(&c->replay_list);
+ INIT_LIST_HEAD(&c->replay_buds);
+ INIT_LIST_HEAD(&c->uncat_list);
+ INIT_LIST_HEAD(&c->empty_list);
+ INIT_LIST_HEAD(&c->freeable_list);
+ INIT_LIST_HEAD(&c->frdi_idx_list);
+ INIT_LIST_HEAD(&c->unclean_leb_list);
+ INIT_LIST_HEAD(&c->old_buds);
+ INIT_LIST_HEAD(&c->orph_list);
+ INIT_LIST_HEAD(&c->orph_new);
+
+ c->highest_inum = UBIFS_FIRST_INO;
+ c->lhead_lnum = c->ltail_lnum = UBIFS_LOG_LNUM;
+
+ ubi_get_volume_info(ubi, &c->vi);
+ ubi_get_device_info(c->vi.ubi_num, &c->di);
+
+ /* Re-open the UBI device in read-write mode */
+ c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
+ if (IS_ERR(c->ubi)) {
+ err = PTR_ERR(c->ubi);
+ goto out_free;
+ }
+
+ c->vfs_sb = sb;
+
+ sb->s_fs_info = c;
+ sb->s_magic = UBIFS_SUPER_MAGIC;
+ sb->s_blocksize = UBIFS_BLOCK_SIZE;
+ sb->s_blocksize_bits = UBIFS_BLOCK_SHIFT;
+ sb->s_dev = c->vi.cdev;
+ sb->s_maxbytes = c->max_inode_sz = key_max_inode_size(c);
+ if (c->max_inode_sz > MAX_LFS_FILESIZE)
+ sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE;
+
+ mutex_lock(&c->umount_mutex);
+ err = mount_ubifs(c);
+ if (err) {
+ ubifs_assert(err < 0);
+ goto out_unlock;
+ }
+
+ /* Read the root inode */
+ root = ubifs_iget(sb, UBIFS_ROOT_INO);
+ if (IS_ERR(root)) {
+ err = PTR_ERR(root);
+ goto out_umount;
+ }
+
+ sb->s_root = NULL;
+
+ mutex_unlock(&c->umount_mutex);
+ return 0;
+
+out_umount:
+ ubifs_umount(c);
+out_unlock:
+ mutex_unlock(&c->umount_mutex);
+ ubi_close_volume(c->ubi);
+out_free:
+ kfree(c);
+ return err;
+}
+
+static int sb_test(struct super_block *sb, void *data)
+{
+ dev_t *dev = data;
+
+ return sb->s_dev == *dev;
+}
+
+static int ubifs_get_sb(struct file_system_type *fs_type, int flags,
+ const char *name, void *data, struct vfsmount *mnt)
+{
+ struct ubi_volume_desc *ubi;
+ struct ubi_volume_info vi;
+ struct super_block *sb;
+ int err;
+
+ dbg_gen("name %s, flags %#x", name, flags);
+
+ /*
+ * Get UBI device number and volume ID. Mount it read-only so far
+ * because this might be a new mount point, and UBI allows only one
+ * read-write user at a time.
+ */
+ ubi = open_ubi(name, UBI_READONLY);
+ if (IS_ERR(ubi)) {
+ ubifs_err("cannot open \"%s\", error %d",
+ name, (int)PTR_ERR(ubi));
+ return PTR_ERR(ubi);
+ }
+ ubi_get_volume_info(ubi, &vi);
+
+ dbg_gen("opened ubi%d_%d", vi.ubi_num, vi.vol_id);
+
+ sb = sget(fs_type, &sb_test, &sb_set, &vi.cdev);
+ if (IS_ERR(sb)) {
+ err = PTR_ERR(sb);
+ goto out_close;
+ }
+
+ if (sb->s_root) {
+ /* A new mount point for already mounted UBIFS */
+ dbg_gen("this ubi volume is already mounted");
+ if ((flags ^ sb->s_flags) & MS_RDONLY) {
+ err = -EBUSY;
+ goto out_deact;
+ }
+ } else {
+ sb->s_flags = flags;
+ /*
+ * Pass 'ubi' to 'fill_super()' in sb->s_fs_info where it is
+ * replaced by 'c'.
+ */
+ sb->s_fs_info = ubi;
+ err = ubifs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
+ if (err)
+ goto out_deact;
+ /* We do not support atime */
+ sb->s_flags |= MS_ACTIVE | MS_NOATIME;
+ }
+
+ /* 'fill_super()' opens ubi again so we must close it here */
+ ubi_close_volume(ubi);
+
+ ubifs_sb = sb;
+ return 0;
+
+out_deact:
+ up_write(&sb->s_umount);
+out_close:
+ ubi_close_volume(ubi);
+ return err;
+}
+
+int __init ubifs_init(void)
+{
+ int err;
+
+ BUILD_BUG_ON(sizeof(struct ubifs_ch) != 24);
+
+ /* Make sure node sizes are 8-byte aligned */
+ BUILD_BUG_ON(UBIFS_CH_SZ & 7);
+ BUILD_BUG_ON(UBIFS_INO_NODE_SZ & 7);
+ BUILD_BUG_ON(UBIFS_DENT_NODE_SZ & 7);
+ BUILD_BUG_ON(UBIFS_XENT_NODE_SZ & 7);
+ BUILD_BUG_ON(UBIFS_DATA_NODE_SZ & 7);
+ BUILD_BUG_ON(UBIFS_TRUN_NODE_SZ & 7);
+ BUILD_BUG_ON(UBIFS_SB_NODE_SZ & 7);
+ BUILD_BUG_ON(UBIFS_MST_NODE_SZ & 7);
+ BUILD_BUG_ON(UBIFS_REF_NODE_SZ & 7);
+ BUILD_BUG_ON(UBIFS_CS_NODE_SZ & 7);
+ BUILD_BUG_ON(UBIFS_ORPH_NODE_SZ & 7);
+
+ BUILD_BUG_ON(UBIFS_MAX_DENT_NODE_SZ & 7);
+ BUILD_BUG_ON(UBIFS_MAX_XENT_NODE_SZ & 7);
+ BUILD_BUG_ON(UBIFS_MAX_DATA_NODE_SZ & 7);
+ BUILD_BUG_ON(UBIFS_MAX_INO_NODE_SZ & 7);
+ BUILD_BUG_ON(UBIFS_MAX_NODE_SZ & 7);
+ BUILD_BUG_ON(MIN_WRITE_SZ & 7);
+
+ /* Check min. node size */
+ BUILD_BUG_ON(UBIFS_INO_NODE_SZ < MIN_WRITE_SZ);
+ BUILD_BUG_ON(UBIFS_DENT_NODE_SZ < MIN_WRITE_SZ);
+ BUILD_BUG_ON(UBIFS_XENT_NODE_SZ < MIN_WRITE_SZ);
+ BUILD_BUG_ON(UBIFS_TRUN_NODE_SZ < MIN_WRITE_SZ);
+
+ BUILD_BUG_ON(UBIFS_MAX_DENT_NODE_SZ > UBIFS_MAX_NODE_SZ);
+ BUILD_BUG_ON(UBIFS_MAX_XENT_NODE_SZ > UBIFS_MAX_NODE_SZ);
+ BUILD_BUG_ON(UBIFS_MAX_DATA_NODE_SZ > UBIFS_MAX_NODE_SZ);
+ BUILD_BUG_ON(UBIFS_MAX_INO_NODE_SZ > UBIFS_MAX_NODE_SZ);
+
+ /* Defined node sizes */
+ BUILD_BUG_ON(UBIFS_SB_NODE_SZ != 4096);
+ BUILD_BUG_ON(UBIFS_MST_NODE_SZ != 512);
+ BUILD_BUG_ON(UBIFS_INO_NODE_SZ != 160);
+ BUILD_BUG_ON(UBIFS_REF_NODE_SZ != 64);
+
+ /*
+ * We use 2 bit wide bit-fields to store compression type, which should
+ * be amended if more compressors are added. The bit-fields are:
+ * @compr_type in 'struct ubifs_inode', @default_compr in
+ * 'struct ubifs_info' and @compr_type in 'struct ubifs_mount_opts'.
+ */
+ BUILD_BUG_ON(UBIFS_COMPR_TYPES_CNT > 4);
+
+ /*
+ * We require that PAGE_CACHE_SIZE is greater-than-or-equal-to
+ * UBIFS_BLOCK_SIZE. It is assumed that both are powers of 2.
+ */
+ if (PAGE_CACHE_SIZE < UBIFS_BLOCK_SIZE) {
+ ubifs_err("VFS page cache size is %u bytes, but UBIFS requires"
+ " at least 4096 bytes",
+ (unsigned int)PAGE_CACHE_SIZE);
+ return -EINVAL;
+ }
+
+ err = -ENOMEM;
+
+ err = ubifs_compressors_init();
+ if (err)
+ goto out_shrinker;
+
+ return 0;
+
+out_shrinker:
+ return err;
+}
+
+/*
+ * ubifsmount...
+ */
+
+static struct file_system_type ubifs_fs_type = {
+ .name = "ubifs",
+ .owner = THIS_MODULE,
+ .get_sb = ubifs_get_sb,
+};
+
+int ubifs_mount(char *vol_name)
+{
+ int flags;
+ char name[80] = "ubi:";
+ void *data;
+ struct vfsmount *mnt;
+ int ret;
+ struct ubifs_info *c;
+
+ /*
+ * First unmount if allready mounted
+ */
+ if (ubifs_sb)
+ ubifs_umount(ubifs_sb->s_fs_info);
+
+ INIT_LIST_HEAD(&ubifs_infos);
+
+ /*
+ * Mount in read-only mode
+ */
+ flags = MS_RDONLY;
+ strcat(name, vol_name);
+ data = NULL;
+ mnt = NULL;
+ ret = ubifs_get_sb(&ubifs_fs_type, flags, name, data, mnt);
+ if (ret) {
+ printf("Error reading superblock on volume '%s'!\n", name);
+ return -1;
+ }
+
+ c = ubifs_sb->s_fs_info;
+ ubi_close_volume(c->ubi);
+
+ return 0;
+}
diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
new file mode 100644
index 0000000..ccda938
--- /dev/null
+++ b/fs/ubifs/tnc.c
@@ -0,0 +1,2767 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ * Artem Bityutskiy (Битюцкий Ðртём)
+ */
+
+/*
+ * This file implements TNC (Tree Node Cache) which caches indexing nodes of
+ * the UBIFS B-tree.
+ *
+ * At the moment the locking rules of the TNC tree are quite simple and
+ * straightforward. We just have a mutex and lock it when we traverse the
+ * tree. If a znode is not in memory, we read it from flash while still having
+ * the mutex locked.
+ */
+
+#include "ubifs.h"
+
+/*
+ * Returned codes of 'matches_name()' and 'fallible_matches_name()' functions.
+ * @NAME_LESS: name corresponding to the first argument is less than second
+ * @NAME_MATCHES: names match
+ * @NAME_GREATER: name corresponding to the second argument is greater than
+ * first
+ * @NOT_ON_MEDIA: node referred by zbranch does not exist on the media
+ *
+ * These constants were introduce to improve readability.
+ */
+enum {
+ NAME_LESS = 0,
+ NAME_MATCHES = 1,
+ NAME_GREATER = 2,
+ NOT_ON_MEDIA = 3,
+};
+
+/**
+ * insert_old_idx - record an index node obsoleted since the last commit start.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number of obsoleted index node
+ * @offs: offset of obsoleted index node
+ *
+ * Returns %0 on success, and a negative error code on failure.
+ *
+ * For recovery, there must always be a complete intact version of the index on
+ * flash at all times. That is called the "old index". It is the index as at the
+ * time of the last successful commit. Many of the index nodes in the old index
+ * may be dirty, but they must not be erased until the next successful commit
+ * (at which point that index becomes the old index).
+ *
+ * That means that the garbage collection and the in-the-gaps method of
+ * committing must be able to determine if an index node is in the old index.
+ * Most of the old index nodes can be found by looking up the TNC using the
+ * 'lookup_znode()' function. However, some of the old index nodes may have
+ * been deleted from the current index or may have been changed so much that
+ * they cannot be easily found. In those cases, an entry is added to an RB-tree.
+ * That is what this function does. The RB-tree is ordered by LEB number and
+ * offset because they uniquely identify the old index node.
+ */
+static int insert_old_idx(struct ubifs_info *c, int lnum, int offs)
+{
+ struct ubifs_old_idx *old_idx, *o;
+ struct rb_node **p, *parent = NULL;
+
+ old_idx = kmalloc(sizeof(struct ubifs_old_idx), GFP_NOFS);
+ if (unlikely(!old_idx))
+ return -ENOMEM;
+ old_idx->lnum = lnum;
+ old_idx->offs = offs;
+
+ p = &c->old_idx.rb_node;
+ while (*p) {
+ parent = *p;
+ o = rb_entry(parent, struct ubifs_old_idx, rb);
+ if (lnum < o->lnum)
+ p = &(*p)->rb_left;
+ else if (lnum > o->lnum)
+ p = &(*p)->rb_right;
+ else if (offs < o->offs)
+ p = &(*p)->rb_left;
+ else if (offs > o->offs)
+ p = &(*p)->rb_right;
+ else {
+ ubifs_err("old idx added twice!");
+ kfree(old_idx);
+ return 0;
+ }
+ }
+ rb_link_node(&old_idx->rb, parent, p);
+ rb_insert_color(&old_idx->rb, &c->old_idx);
+ return 0;
+}
+
+/**
+ * insert_old_idx_znode - record a znode obsoleted since last commit start.
+ * @c: UBIFS file-system description object
+ * @znode: znode of obsoleted index node
+ *
+ * Returns %0 on success, and a negative error code on failure.
+ */
+int insert_old_idx_znode(struct ubifs_info *c, struct ubifs_znode *znode)
+{
+ if (znode->parent) {
+ struct ubifs_zbranch *zbr;
+
+ zbr = &znode->parent->zbranch[znode->iip];
+ if (zbr->len)
+ return insert_old_idx(c, zbr->lnum, zbr->offs);
+ } else
+ if (c->zroot.len)
+ return insert_old_idx(c, c->zroot.lnum,
+ c->zroot.offs);
+ return 0;
+}
+
+/**
+ * ins_clr_old_idx_znode - record a znode obsoleted since last commit start.
+ * @c: UBIFS file-system description object
+ * @znode: znode of obsoleted index node
+ *
+ * Returns %0 on success, and a negative error code on failure.
+ */
+static int ins_clr_old_idx_znode(struct ubifs_info *c,
+ struct ubifs_znode *znode)
+{
+ int err;
+
+ if (znode->parent) {
+ struct ubifs_zbranch *zbr;
+
+ zbr = &znode->parent->zbranch[znode->iip];
+ if (zbr->len) {
+ err = insert_old_idx(c, zbr->lnum, zbr->offs);
+ if (err)
+ return err;
+ zbr->lnum = 0;
+ zbr->offs = 0;
+ zbr->len = 0;
+ }
+ } else
+ if (c->zroot.len) {
+ err = insert_old_idx(c, c->zroot.lnum, c->zroot.offs);
+ if (err)
+ return err;
+ c->zroot.lnum = 0;
+ c->zroot.offs = 0;
+ c->zroot.len = 0;
+ }
+ return 0;
+}
+
+/**
+ * destroy_old_idx - destroy the old_idx RB-tree.
+ * @c: UBIFS file-system description object
+ *
+ * During start commit, the old_idx RB-tree is used to avoid overwriting index
+ * nodes that were in the index last commit but have since been deleted. This
+ * is necessary for recovery i.e. the old index must be kept intact until the
+ * new index is successfully written. The old-idx RB-tree is used for the
+ * in-the-gaps method of writing index nodes and is destroyed every commit.
+ */
+void destroy_old_idx(struct ubifs_info *c)
+{
+ struct rb_node *this = c->old_idx.rb_node;
+ struct ubifs_old_idx *old_idx;
+
+ while (this) {
+ if (this->rb_left) {
+ this = this->rb_left;
+ continue;
+ } else if (this->rb_right) {
+ this = this->rb_right;
+ continue;
+ }
+ old_idx = rb_entry(this, struct ubifs_old_idx, rb);
+ this = rb_parent(this);
+ if (this) {
+ if (this->rb_left == &old_idx->rb)
+ this->rb_left = NULL;
+ else
+ this->rb_right = NULL;
+ }
+ kfree(old_idx);
+ }
+ c->old_idx = RB_ROOT;
+}
+
+/**
+ * copy_znode - copy a dirty znode.
+ * @c: UBIFS file-system description object
+ * @znode: znode to copy
+ *
+ * A dirty znode being committed may not be changed, so it is copied.
+ */
+static struct ubifs_znode *copy_znode(struct ubifs_info *c,
+ struct ubifs_znode *znode)
+{
+ struct ubifs_znode *zn;
+
+ zn = kmalloc(c->max_znode_sz, GFP_NOFS);
+ if (unlikely(!zn))
+ return ERR_PTR(-ENOMEM);
+
+ memcpy(zn, znode, c->max_znode_sz);
+ zn->cnext = NULL;
+ __set_bit(DIRTY_ZNODE, &zn->flags);
+ __clear_bit(COW_ZNODE, &zn->flags);
+
+ ubifs_assert(!test_bit(OBSOLETE_ZNODE, &znode->flags));
+ __set_bit(OBSOLETE_ZNODE, &znode->flags);
+
+ if (znode->level != 0) {
+ int i;
+ const int n = zn->child_cnt;
+
+ /* The children now have new parent */
+ for (i = 0; i < n; i++) {
+ struct ubifs_zbranch *zbr = &zn->zbranch[i];
+
+ if (zbr->znode)
+ zbr->znode->parent = zn;
+ }
+ }
+
+ atomic_long_inc(&c->dirty_zn_cnt);
+ return zn;
+}
+
+/**
+ * add_idx_dirt - add dirt due to a dirty znode.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number of index node
+ * @dirt: size of index node
+ *
+ * This function updates lprops dirty space and the new size of the index.
+ */
+static int add_idx_dirt(struct ubifs_info *c, int lnum, int dirt)
+{
+ c->calc_idx_sz -= ALIGN(dirt, 8);
+ return ubifs_add_dirt(c, lnum, dirt);
+}
+
+/**
+ * dirty_cow_znode - ensure a znode is not being committed.
+ * @c: UBIFS file-system description object
+ * @zbr: branch of znode to check
+ *
+ * Returns dirtied znode on success or negative error code on failure.
+ */
+static struct ubifs_znode *dirty_cow_znode(struct ubifs_info *c,
+ struct ubifs_zbranch *zbr)
+{
+ struct ubifs_znode *znode = zbr->znode;
+ struct ubifs_znode *zn;
+ int err;
+
+ if (!test_bit(COW_ZNODE, &znode->flags)) {
+ /* znode is not being committed */
+ if (!test_and_set_bit(DIRTY_ZNODE, &znode->flags)) {
+ atomic_long_inc(&c->dirty_zn_cnt);
+ atomic_long_dec(&c->clean_zn_cnt);
+ atomic_long_dec(&ubifs_clean_zn_cnt);
+ err = add_idx_dirt(c, zbr->lnum, zbr->len);
+ if (unlikely(err))
+ return ERR_PTR(err);
+ }
+ return znode;
+ }
+
+ zn = copy_znode(c, znode);
+ if (IS_ERR(zn))
+ return zn;
+
+ if (zbr->len) {
+ err = insert_old_idx(c, zbr->lnum, zbr->offs);
+ if (unlikely(err))
+ return ERR_PTR(err);
+ err = add_idx_dirt(c, zbr->lnum, zbr->len);
+ } else
+ err = 0;
+
+ zbr->znode = zn;
+ zbr->lnum = 0;
+ zbr->offs = 0;
+ zbr->len = 0;
+
+ if (unlikely(err))
+ return ERR_PTR(err);
+ return zn;
+}
+
+/**
+ * lnc_add - add a leaf node to the leaf node cache.
+ * @c: UBIFS file-system description object
+ * @zbr: zbranch of leaf node
+ * @node: leaf node
+ *
+ * Leaf nodes are non-index nodes directory entry nodes or data nodes. The
+ * purpose of the leaf node cache is to save re-reading the same leaf node over
+ * and over again. Most things are cached by VFS, however the file system must
+ * cache directory entries for readdir and for resolving hash collisions. The
+ * present implementation of the leaf node cache is extremely simple, and
+ * allows for error returns that are not used but that may be needed if a more
+ * complex implementation is created.
+ *
+ * Note, this function does not add the @node object to LNC directly, but
+ * allocates a copy of the object and adds the copy to LNC. The reason for this
+ * is that @node has been allocated outside of the TNC subsystem and will be
+ * used with @c->tnc_mutex unlock upon return from the TNC subsystem. But LNC
+ * may be changed at any time, e.g. freed by the shrinker.
+ */
+static int lnc_add(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+ const void *node)
+{
+ int err;
+ void *lnc_node;
+ const struct ubifs_dent_node *dent = node;
+
+ ubifs_assert(!zbr->leaf);
+ ubifs_assert(zbr->len != 0);
+ ubifs_assert(is_hash_key(c, &zbr->key));
+
+ err = ubifs_validate_entry(c, dent);
+ if (err) {
+ dbg_dump_stack();
+ dbg_dump_node(c, dent);
+ return err;
+ }
+
+ lnc_node = kmalloc(zbr->len, GFP_NOFS);
+ if (!lnc_node)
+ /* We don't have to have the cache, so no error */
+ return 0;
+
+ memcpy(lnc_node, node, zbr->len);
+ zbr->leaf = lnc_node;
+ return 0;
+}
+
+ /**
+ * lnc_add_directly - add a leaf node to the leaf-node-cache.
+ * @c: UBIFS file-system description object
+ * @zbr: zbranch of leaf node
+ * @node: leaf node
+ *
+ * This function is similar to 'lnc_add()', but it does not create a copy of
+ * @node but inserts @node to TNC directly.
+ */
+static int lnc_add_directly(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+ void *node)
+{
+ int err;
+
+ ubifs_assert(!zbr->leaf);
+ ubifs_assert(zbr->len != 0);
+
+ err = ubifs_validate_entry(c, node);
+ if (err) {
+ dbg_dump_stack();
+ dbg_dump_node(c, node);
+ return err;
+ }
+
+ zbr->leaf = node;
+ return 0;
+}
+
+/**
+ * lnc_free - remove a leaf node from the leaf node cache.
+ * @zbr: zbranch of leaf node
+ * @node: leaf node
+ */
+static void lnc_free(struct ubifs_zbranch *zbr)
+{
+ if (!zbr->leaf)
+ return;
+ kfree(zbr->leaf);
+ zbr->leaf = NULL;
+}
+
+/**
+ * tnc_read_node_nm - read a "hashed" leaf node.
+ * @c: UBIFS file-system description object
+ * @zbr: key and position of the node
+ * @node: node is returned here
+ *
+ * This function reads a "hashed" node defined by @zbr from the leaf node cache
+ * (in it is there) or from the hash media, in which case the node is also
+ * added to LNC. Returns zero in case of success or a negative negative error
+ * code in case of failure.
+ */
+static int tnc_read_node_nm(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+ void *node)
+{
+ int err;
+
+ ubifs_assert(is_hash_key(c, &zbr->key));
+
+ if (zbr->leaf) {
+ /* Read from the leaf node cache */
+ ubifs_assert(zbr->len != 0);
+ memcpy(node, zbr->leaf, zbr->len);
+ return 0;
+ }
+
+ err = ubifs_tnc_read_node(c, zbr, node);
+ if (err)
+ return err;
+
+ /* Add the node to the leaf node cache */
+ err = lnc_add(c, zbr, node);
+ return err;
+}
+
+/**
+ * try_read_node - read a node if it is a node.
+ * @c: UBIFS file-system description object
+ * @buf: buffer to read to
+ * @type: node type
+ * @len: node length (not aligned)
+ * @lnum: LEB number of node to read
+ * @offs: offset of node to read
+ *
+ * This function tries to read a node of known type and length, checks it and
+ * stores it in @buf. This function returns %1 if a node is present and %0 if
+ * a node is not present. A negative error code is returned for I/O errors.
+ * This function performs that same function as ubifs_read_node except that
+ * it does not require that there is actually a node present and instead
+ * the return code indicates if a node was read.
+ *
+ * Note, this function does not check CRC of data nodes if @c->no_chk_data_crc
+ * is true (it is controlled by corresponding mount option). However, if
+ * @c->always_chk_crc is true, @c->no_chk_data_crc is ignored and CRC is always
+ * checked.
+ */
+static int try_read_node(const struct ubifs_info *c, void *buf, int type,
+ int len, int lnum, int offs)
+{
+ int err, node_len;
+ struct ubifs_ch *ch = buf;
+ uint32_t crc, node_crc;
+
+ dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len);
+
+ err = ubi_read(c->ubi, lnum, buf, offs, len);
+ if (err) {
+ ubifs_err("cannot read node type %d from LEB %d:%d, error %d",
+ type, lnum, offs, err);
+ return err;
+ }
+
+ if (le32_to_cpu(ch->magic) != UBIFS_NODE_MAGIC)
+ return 0;
+
+ if (ch->node_type != type)
+ return 0;
+
+ node_len = le32_to_cpu(ch->len);
+ if (node_len != len)
+ return 0;
+
+ if (type == UBIFS_DATA_NODE && !c->always_chk_crc && c->no_chk_data_crc)
+ return 1;
+
+ crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
+ node_crc = le32_to_cpu(ch->crc);
+ if (crc != node_crc)
+ return 0;
+
+ return 1;
+}
+
+/**
+ * fallible_read_node - try to read a leaf node.
+ * @c: UBIFS file-system description object
+ * @key: key of node to read
+ * @zbr: position of node
+ * @node: node returned
+ *
+ * This function tries to read a node and returns %1 if the node is read, %0
+ * if the node is not present, and a negative error code in the case of error.
+ */
+static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
+ struct ubifs_zbranch *zbr, void *node)
+{
+ int ret;
+
+ dbg_tnc("LEB %d:%d, key %s", zbr->lnum, zbr->offs, DBGKEY(key));
+
+ ret = try_read_node(c, node, key_type(c, key), zbr->len, zbr->lnum,
+ zbr->offs);
+ if (ret == 1) {
+ union ubifs_key node_key;
+ struct ubifs_dent_node *dent = node;
+
+ /* All nodes have key in the same place */
+ key_read(c, &dent->key, &node_key);
+ if (keys_cmp(c, key, &node_key) != 0)
+ ret = 0;
+ }
+ if (ret == 0 && c->replaying)
+ dbg_mnt("dangling branch LEB %d:%d len %d, key %s",
+ zbr->lnum, zbr->offs, zbr->len, DBGKEY(key));
+ return ret;
+}
+
+/**
+ * matches_name - determine if a direntry or xattr entry matches a given name.
+ * @c: UBIFS file-system description object
+ * @zbr: zbranch of dent
+ * @nm: name to match
+ *
+ * This function checks if xentry/direntry referred by zbranch @zbr matches name
+ * @nm. Returns %NAME_MATCHES if it does, %NAME_LESS if the name referred by
+ * @zbr is less than @nm, and %NAME_GREATER if it is greater than @nm. In case
+ * of failure, a negative error code is returned.
+ */
+static int matches_name(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+ const struct qstr *nm)
+{
+ struct ubifs_dent_node *dent;
+ int nlen, err;
+
+ /* If possible, match against the dent in the leaf node cache */
+ if (!zbr->leaf) {
+ dent = kmalloc(zbr->len, GFP_NOFS);
+ if (!dent)
+ return -ENOMEM;
+
+ err = ubifs_tnc_read_node(c, zbr, dent);
+ if (err)
+ goto out_free;
+
+ /* Add the node to the leaf node cache */
+ err = lnc_add_directly(c, zbr, dent);
+ if (err)
+ goto out_free;
+ } else
+ dent = zbr->leaf;
+
+ nlen = le16_to_cpu(dent->nlen);
+ err = memcmp(dent->name, nm->name, min_t(int, nlen, nm->len));
+ if (err == 0) {
+ if (nlen == nm->len)
+ return NAME_MATCHES;
+ else if (nlen < nm->len)
+ return NAME_LESS;
+ else
+ return NAME_GREATER;
+ } else if (err < 0)
+ return NAME_LESS;
+ else
+ return NAME_GREATER;
+
+out_free:
+ kfree(dent);
+ return err;
+}
+
+/**
+ * get_znode - get a TNC znode that may not be loaded yet.
+ * @c: UBIFS file-system description object
+ * @znode: parent znode
+ * @n: znode branch slot number
+ *
+ * This function returns the znode or a negative error code.
+ */
+static struct ubifs_znode *get_znode(struct ubifs_info *c,
+ struct ubifs_znode *znode, int n)
+{
+ struct ubifs_zbranch *zbr;
+
+ zbr = &znode->zbranch[n];
+ if (zbr->znode)
+ znode = zbr->znode;
+ else
+ znode = ubifs_load_znode(c, zbr, znode, n);
+ return znode;
+}
+
+/**
+ * tnc_next - find next TNC entry.
+ * @c: UBIFS file-system description object
+ * @zn: znode is passed and returned here
+ * @n: znode branch slot number is passed and returned here
+ *
+ * This function returns %0 if the next TNC entry is found, %-ENOENT if there is
+ * no next entry, or a negative error code otherwise.
+ */
+static int tnc_next(struct ubifs_info *c, struct ubifs_znode **zn, int *n)
+{
+ struct ubifs_znode *znode = *zn;
+ int nn = *n;
+
+ nn += 1;
+ if (nn < znode->child_cnt) {
+ *n = nn;
+ return 0;
+ }
+ while (1) {
+ struct ubifs_znode *zp;
+
+ zp = znode->parent;
+ if (!zp)
+ return -ENOENT;
+ nn = znode->iip + 1;
+ znode = zp;
+ if (nn < znode->child_cnt) {
+ znode = get_znode(c, znode, nn);
+ if (IS_ERR(znode))
+ return PTR_ERR(znode);
+ while (znode->level != 0) {
+ znode = get_znode(c, znode, 0);
+ if (IS_ERR(znode))
+ return PTR_ERR(znode);
+ }
+ nn = 0;
+ break;
+ }
+ }
+ *zn = znode;
+ *n = nn;
+ return 0;
+}
+
+/**
+ * tnc_prev - find previous TNC entry.
+ * @c: UBIFS file-system description object
+ * @zn: znode is returned here
+ * @n: znode branch slot number is passed and returned here
+ *
+ * This function returns %0 if the previous TNC entry is found, %-ENOENT if
+ * there is no next entry, or a negative error code otherwise.
+ */
+static int tnc_prev(struct ubifs_info *c, struct ubifs_znode **zn, int *n)
+{
+ struct ubifs_znode *znode = *zn;
+ int nn = *n;
+
+ if (nn > 0) {
+ *n = nn - 1;
+ return 0;
+ }
+ while (1) {
+ struct ubifs_znode *zp;
+
+ zp = znode->parent;
+ if (!zp)
+ return -ENOENT;
+ nn = znode->iip - 1;
+ znode = zp;
+ if (nn >= 0) {
+ znode = get_znode(c, znode, nn);
+ if (IS_ERR(znode))
+ return PTR_ERR(znode);
+ while (znode->level != 0) {
+ nn = znode->child_cnt - 1;
+ znode = get_znode(c, znode, nn);
+ if (IS_ERR(znode))
+ return PTR_ERR(znode);
+ }
+ nn = znode->child_cnt - 1;
+ break;
+ }
+ }
+ *zn = znode;
+ *n = nn;
+ return 0;
+}
+
+/**
+ * resolve_collision - resolve a collision.
+ * @c: UBIFS file-system description object
+ * @key: key of a directory or extended attribute entry
+ * @zn: znode is returned here
+ * @n: zbranch number is passed and returned here
+ * @nm: name of the entry
+ *
+ * This function is called for "hashed" keys to make sure that the found key
+ * really corresponds to the looked up node (directory or extended attribute
+ * entry). It returns %1 and sets @zn and @n if the collision is resolved.
+ * %0 is returned if @nm is not found and @zn and @n are set to the previous
+ * entry, i.e. to the entry after which @nm could follow if it were in TNC.
+ * This means that @n may be set to %-1 if the leftmost key in @zn is the
+ * previous one. A negative error code is returned on failures.
+ */
+static int resolve_collision(struct ubifs_info *c, const union ubifs_key *key,
+ struct ubifs_znode **zn, int *n,
+ const struct qstr *nm)
+{
+ int err;
+
+ err = matches_name(c, &(*zn)->zbranch[*n], nm);
+ if (unlikely(err < 0))
+ return err;
+ if (err == NAME_MATCHES)
+ return 1;
+
+ if (err == NAME_GREATER) {
+ /* Look left */
+ while (1) {
+ err = tnc_prev(c, zn, n);
+ if (err == -ENOENT) {
+ ubifs_assert(*n == 0);
+ *n = -1;
+ return 0;
+ }
+ if (err < 0)
+ return err;
+ if (keys_cmp(c, &(*zn)->zbranch[*n].key, key)) {
+ /*
+ * We have found the branch after which we would
+ * like to insert, but inserting in this znode
+ * may still be wrong. Consider the following 3
+ * znodes, in the case where we are resolving a
+ * collision with Key2.
+ *
+ * znode zp
+ * ----------------------
+ * level 1 | Key0 | Key1 |
+ * -----------------------
+ * | |
+ * znode za | | znode zb
+ * ------------ ------------
+ * level 0 | Key0 | | Key2 |
+ * ------------ ------------
+ *
+ * The lookup finds Key2 in znode zb. Lets say
+ * there is no match and the name is greater so
+ * we look left. When we find Key0, we end up
+ * here. If we return now, we will insert into
+ * znode za at slot n = 1. But that is invalid
+ * according to the parent's keys. Key2 must
+ * be inserted into znode zb.
+ *
+ * Note, this problem is not relevant for the
+ * case when we go right, because
+ * 'tnc_insert()' would correct the parent key.
+ */
+ if (*n == (*zn)->child_cnt - 1) {
+ err = tnc_next(c, zn, n);
+ if (err) {
+ /* Should be impossible */
+ ubifs_assert(0);
+ if (err == -ENOENT)
+ err = -EINVAL;
+ return err;
+ }
+ ubifs_assert(*n == 0);
+ *n = -1;
+ }
+ return 0;
+ }
+ err = matches_name(c, &(*zn)->zbranch[*n], nm);
+ if (err < 0)
+ return err;
+ if (err == NAME_LESS)
+ return 0;
+ if (err == NAME_MATCHES)
+ return 1;
+ ubifs_assert(err == NAME_GREATER);
+ }
+ } else {
+ int nn = *n;
+ struct ubifs_znode *znode = *zn;
+
+ /* Look right */
+ while (1) {
+ err = tnc_next(c, &znode, &nn);
+ if (err == -ENOENT)
+ return 0;
+ if (err < 0)
+ return err;
+ if (keys_cmp(c, &znode->zbranch[nn].key, key))
+ return 0;
+ err = matches_name(c, &znode->zbranch[nn], nm);
+ if (err < 0)
+ return err;
+ if (err == NAME_GREATER)
+ return 0;
+ *zn = znode;
+ *n = nn;
+ if (err == NAME_MATCHES)
+ return 1;
+ ubifs_assert(err == NAME_LESS);
+ }
+ }
+}
+
+/**
+ * fallible_matches_name - determine if a dent matches a given name.
+ * @c: UBIFS file-system description object
+ * @zbr: zbranch of dent
+ * @nm: name to match
+ *
+ * This is a "fallible" version of 'matches_name()' function which does not
+ * panic if the direntry/xentry referred by @zbr does not exist on the media.
+ *
+ * This function checks if xentry/direntry referred by zbranch @zbr matches name
+ * @nm. Returns %NAME_MATCHES it does, %NAME_LESS if the name referred by @zbr
+ * is less than @nm, %NAME_GREATER if it is greater than @nm, and @NOT_ON_MEDIA
+ * if xentry/direntry referred by @zbr does not exist on the media. A negative
+ * error code is returned in case of failure.
+ */
+static int fallible_matches_name(struct ubifs_info *c,
+ struct ubifs_zbranch *zbr,
+ const struct qstr *nm)
+{
+ struct ubifs_dent_node *dent;
+ int nlen, err;
+
+ /* If possible, match against the dent in the leaf node cache */
+ if (!zbr->leaf) {
+ dent = kmalloc(zbr->len, GFP_NOFS);
+ if (!dent)
+ return -ENOMEM;
+
+ err = fallible_read_node(c, &zbr->key, zbr, dent);
+ if (err < 0)
+ goto out_free;
+ if (err == 0) {
+ /* The node was not present */
+ err = NOT_ON_MEDIA;
+ goto out_free;
+ }
+ ubifs_assert(err == 1);
+
+ err = lnc_add_directly(c, zbr, dent);
+ if (err)
+ goto out_free;
+ } else
+ dent = zbr->leaf;
+
+ nlen = le16_to_cpu(dent->nlen);
+ err = memcmp(dent->name, nm->name, min_t(int, nlen, nm->len));
+ if (err == 0) {
+ if (nlen == nm->len)
+ return NAME_MATCHES;
+ else if (nlen < nm->len)
+ return NAME_LESS;
+ else
+ return NAME_GREATER;
+ } else if (err < 0)
+ return NAME_LESS;
+ else
+ return NAME_GREATER;
+
+out_free:
+ kfree(dent);
+ return err;
+}
+
+/**
+ * fallible_resolve_collision - resolve a collision even if nodes are missing.
+ * @c: UBIFS file-system description object
+ * @key: key
+ * @zn: znode is returned here
+ * @n: branch number is passed and returned here
+ * @nm: name of directory entry
+ * @adding: indicates caller is adding a key to the TNC
+ *
+ * This is a "fallible" version of the 'resolve_collision()' function which
+ * does not panic if one of the nodes referred to by TNC does not exist on the
+ * media. This may happen when replaying the journal if a deleted node was
+ * Garbage-collected and the commit was not done. A branch that refers to a node
+ * that is not present is called a dangling branch. The following are the return
+ * codes for this function:
+ * o if @nm was found, %1 is returned and @zn and @n are set to the found
+ * branch;
+ * o if we are @adding and @nm was not found, %0 is returned;
+ * o if we are not @adding and @nm was not found, but a dangling branch was
+ * found, then %1 is returned and @zn and @n are set to the dangling branch;
+ * o a negative error code is returned in case of failure.
+ */
+static int fallible_resolve_collision(struct ubifs_info *c,
+ const union ubifs_key *key,
+ struct ubifs_znode **zn, int *n,
+ const struct qstr *nm, int adding)
+{
+ struct ubifs_znode *o_znode = NULL, *znode = *zn;
+ int uninitialized_var(o_n), err, cmp, unsure = 0, nn = *n;
+
+ cmp = fallible_matches_name(c, &znode->zbranch[nn], nm);
+ if (unlikely(cmp < 0))
+ return cmp;
+ if (cmp == NAME_MATCHES)
+ return 1;
+ if (cmp == NOT_ON_MEDIA) {
+ o_znode = znode;
+ o_n = nn;
+ /*
+ * We are unlucky and hit a dangling branch straight away.
+ * Now we do not really know where to go to find the needed
+ * branch - to the left or to the right. Well, let's try left.
+ */
+ unsure = 1;
+ } else if (!adding)
+ unsure = 1; /* Remove a dangling branch wherever it is */
+
+ if (cmp == NAME_GREATER || unsure) {
+ /* Look left */
+ while (1) {
+ err = tnc_prev(c, zn, n);
+ if (err == -ENOENT) {
+ ubifs_assert(*n == 0);
+ *n = -1;
+ break;
+ }
+ if (err < 0)
+ return err;
+ if (keys_cmp(c, &(*zn)->zbranch[*n].key, key)) {
+ /* See comments in 'resolve_collision()' */
+ if (*n == (*zn)->child_cnt - 1) {
+ err = tnc_next(c, zn, n);
+ if (err) {
+ /* Should be impossible */
+ ubifs_assert(0);
+ if (err == -ENOENT)
+ err = -EINVAL;
+ return err;
+ }
+ ubifs_assert(*n == 0);
+ *n = -1;
+ }
+ break;
+ }
+ err = fallible_matches_name(c, &(*zn)->zbranch[*n], nm);
+ if (err < 0)
+ return err;
+ if (err == NAME_MATCHES)
+ return 1;
+ if (err == NOT_ON_MEDIA) {
+ o_znode = *zn;
+ o_n = *n;
+ continue;
+ }
+ if (!adding)
+ continue;
+ if (err == NAME_LESS)
+ break;
+ else
+ unsure = 0;
+ }
+ }
+
+ if (cmp == NAME_LESS || unsure) {
+ /* Look right */
+ *zn = znode;
+ *n = nn;
+ while (1) {
+ err = tnc_next(c, &znode, &nn);
+ if (err == -ENOENT)
+ break;
+ if (err < 0)
+ return err;
+ if (keys_cmp(c, &znode->zbranch[nn].key, key))
+ break;
+ err = fallible_matches_name(c, &znode->zbranch[nn], nm);
+ if (err < 0)
+ return err;
+ if (err == NAME_GREATER)
+ break;
+ *zn = znode;
+ *n = nn;
+ if (err == NAME_MATCHES)
+ return 1;
+ if (err == NOT_ON_MEDIA) {
+ o_znode = znode;
+ o_n = nn;
+ }
+ }
+ }
+
+ /* Never match a dangling branch when adding */
+ if (adding || !o_znode)
+ return 0;
+
+ dbg_mnt("dangling match LEB %d:%d len %d %s",
+ o_znode->zbranch[o_n].lnum, o_znode->zbranch[o_n].offs,
+ o_znode->zbranch[o_n].len, DBGKEY(key));
+ *zn = o_znode;
+ *n = o_n;
+ return 1;
+}
+
+/**
+ * matches_position - determine if a zbranch matches a given position.
+ * @zbr: zbranch of dent
+ * @lnum: LEB number of dent to match
+ * @offs: offset of dent to match
+ *
+ * This function returns %1 if @lnum:@offs matches, and %0 otherwise.
+ */
+static int matches_position(struct ubifs_zbranch *zbr, int lnum, int offs)
+{
+ if (zbr->lnum == lnum && zbr->offs == offs)
+ return 1;
+ else
+ return 0;
+}
+
+/**
+ * resolve_collision_directly - resolve a collision directly.
+ * @c: UBIFS file-system description object
+ * @key: key of directory entry
+ * @zn: znode is passed and returned here
+ * @n: zbranch number is passed and returned here
+ * @lnum: LEB number of dent node to match
+ * @offs: offset of dent node to match
+ *
+ * This function is used for "hashed" keys to make sure the found directory or
+ * extended attribute entry node is what was looked for. It is used when the
+ * flash address of the right node is known (@lnum:@offs) which makes it much
+ * easier to resolve collisions (no need to read entries and match full
+ * names). This function returns %1 and sets @zn and @n if the collision is
+ * resolved, %0 if @lnum:@offs is not found and @zn and @n are set to the
+ * previous directory entry. Otherwise a negative error code is returned.
+ */
+static int resolve_collision_directly(struct ubifs_info *c,
+ const union ubifs_key *key,
+ struct ubifs_znode **zn, int *n,
+ int lnum, int offs)
+{
+ struct ubifs_znode *znode;
+ int nn, err;
+
+ znode = *zn;
+ nn = *n;
+ if (matches_position(&znode->zbranch[nn], lnum, offs))
+ return 1;
+
+ /* Look left */
+ while (1) {
+ err = tnc_prev(c, &znode, &nn);
+ if (err == -ENOENT)
+ break;
+ if (err < 0)
+ return err;
+ if (keys_cmp(c, &znode->zbranch[nn].key, key))
+ break;
+ if (matches_position(&znode->zbranch[nn], lnum, offs)) {
+ *zn = znode;
+ *n = nn;
+ return 1;
+ }
+ }
+
+ /* Look right */
+ znode = *zn;
+ nn = *n;
+ while (1) {
+ err = tnc_next(c, &znode, &nn);
+ if (err == -ENOENT)
+ return 0;
+ if (err < 0)
+ return err;
+ if (keys_cmp(c, &znode->zbranch[nn].key, key))
+ return 0;
+ *zn = znode;
+ *n = nn;
+ if (matches_position(&znode->zbranch[nn], lnum, offs))
+ return 1;
+ }
+}
+
+/**
+ * dirty_cow_bottom_up - dirty a znode and its ancestors.
+ * @c: UBIFS file-system description object
+ * @znode: znode to dirty
+ *
+ * If we do not have a unique key that resides in a znode, then we cannot
+ * dirty that znode from the top down (i.e. by using lookup_level0_dirty)
+ * This function records the path back to the last dirty ancestor, and then
+ * dirties the znodes on that path.
+ */
+static struct ubifs_znode *dirty_cow_bottom_up(struct ubifs_info *c,
+ struct ubifs_znode *znode)
+{
+ struct ubifs_znode *zp;
+ int *path = c->bottom_up_buf, p = 0;
+
+ ubifs_assert(c->zroot.znode);
+ ubifs_assert(znode);
+ if (c->zroot.znode->level > BOTTOM_UP_HEIGHT) {
+ kfree(c->bottom_up_buf);
+ c->bottom_up_buf = kmalloc(c->zroot.znode->level * sizeof(int),
+ GFP_NOFS);
+ if (!c->bottom_up_buf)
+ return ERR_PTR(-ENOMEM);
+ path = c->bottom_up_buf;
+ }
+ if (c->zroot.znode->level) {
+ /* Go up until parent is dirty */
+ while (1) {
+ int n;
+
+ zp = znode->parent;
+ if (!zp)
+ break;
+ n = znode->iip;
+ ubifs_assert(p < c->zroot.znode->level);
+ path[p++] = n;
+ if (!zp->cnext && ubifs_zn_dirty(znode))
+ break;
+ znode = zp;
+ }
+ }
+
+ /* Come back down, dirtying as we go */
+ while (1) {
+ struct ubifs_zbranch *zbr;
+
+ zp = znode->parent;
+ if (zp) {
+ ubifs_assert(path[p - 1] >= 0);
+ ubifs_assert(path[p - 1] < zp->child_cnt);
+ zbr = &zp->zbranch[path[--p]];
+ znode = dirty_cow_znode(c, zbr);
+ } else {
+ ubifs_assert(znode == c->zroot.znode);
+ znode = dirty_cow_znode(c, &c->zroot);
+ }
+ if (IS_ERR(znode) || !p)
+ break;
+ ubifs_assert(path[p - 1] >= 0);
+ ubifs_assert(path[p - 1] < znode->child_cnt);
+ znode = znode->zbranch[path[p - 1]].znode;
+ }
+
+ return znode;
+}
+
+/**
+ * ubifs_lookup_level0 - search for zero-level znode.
+ * @c: UBIFS file-system description object
+ * @key: key to lookup
+ * @zn: znode is returned here
+ * @n: znode branch slot number is returned here
+ *
+ * This function looks up the TNC tree and search for zero-level znode which
+ * refers key @key. The found zero-level znode is returned in @zn. There are 3
+ * cases:
+ * o exact match, i.e. the found zero-level znode contains key @key, then %1
+ * is returned and slot number of the matched branch is stored in @n;
+ * o not exact match, which means that zero-level znode does not contain
+ * @key, then %0 is returned and slot number of the closed branch is stored
+ * in @n;
+ * o @key is so small that it is even less than the lowest key of the
+ * leftmost zero-level node, then %0 is returned and %0 is stored in @n.
+ *
+ * Note, when the TNC tree is traversed, some znodes may be absent, then this
+ * function reads corresponding indexing nodes and inserts them to TNC. In
+ * case of failure, a negative error code is returned.
+ */
+int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
+ struct ubifs_znode **zn, int *n)
+{
+ int err, exact;
+ struct ubifs_znode *znode;
+ unsigned long time = get_seconds();
+
+ dbg_tnc("search key %s", DBGKEY(key));
+
+ znode = c->zroot.znode;
+ if (unlikely(!znode)) {
+ znode = ubifs_load_znode(c, &c->zroot, NULL, 0);
+ if (IS_ERR(znode))
+ return PTR_ERR(znode);
+ }
+
+ znode->time = time;
+
+ while (1) {
+ struct ubifs_zbranch *zbr;
+
+ exact = ubifs_search_zbranch(c, znode, key, n);
+
+ if (znode->level == 0)
+ break;
+
+ if (*n < 0)
+ *n = 0;
+ zbr = &znode->zbranch[*n];
+
+ if (zbr->znode) {
+ znode->time = time;
+ znode = zbr->znode;
+ continue;
+ }
+
+ /* znode is not in TNC cache, load it from the media */
+ znode = ubifs_load_znode(c, zbr, znode, *n);
+ if (IS_ERR(znode))
+ return PTR_ERR(znode);
+ }
+
+ *zn = znode;
+ if (exact || !is_hash_key(c, key) || *n != -1) {
+ dbg_tnc("found %d, lvl %d, n %d", exact, znode->level, *n);
+ return exact;
+ }
+
+ /*
+ * Here is a tricky place. We have not found the key and this is a
+ * "hashed" key, which may collide. The rest of the code deals with
+ * situations like this:
+ *
+ * | 3 | 5 |
+ * / \
+ * | 3 | 5 | | 6 | 7 | (x)
+ *
+ * Or more a complex example:
+ *
+ * | 1 | 5 |
+ * / \
+ * | 1 | 3 | | 5 | 8 |
+ * \ /
+ * | 5 | 5 | | 6 | 7 | (x)
+ *
+ * In the examples, if we are looking for key "5", we may reach nodes
+ * marked with "(x)". In this case what we have do is to look at the
+ * left and see if there is "5" key there. If there is, we have to
+ * return it.
+ *
+ * Note, this whole situation is possible because we allow to have
+ * elements which are equivalent to the next key in the parent in the
+ * children of current znode. For example, this happens if we split a
+ * znode like this: | 3 | 5 | 5 | 6 | 7 |, which results in something
+ * like this:
+ * | 3 | 5 |
+ * / \
+ * | 3 | 5 | | 5 | 6 | 7 |
+ * ^
+ * And this becomes what is at the first "picture" after key "5" marked
+ * with "^" is removed. What could be done is we could prohibit
+ * splitting in the middle of the colliding sequence. Also, when
+ * removing the leftmost key, we would have to correct the key of the
+ * parent node, which would introduce additional complications. Namely,
+ * if we changed the the leftmost key of the parent znode, the garbage
+ * collector would be unable to find it (GC is doing this when GC'ing
+ * indexing LEBs). Although we already have an additional RB-tree where
+ * we save such changed znodes (see 'ins_clr_old_idx_znode()') until
+ * after the commit. But anyway, this does not look easy to implement
+ * so we did not try this.
+ */
+ err = tnc_prev(c, &znode, n);
+ if (err == -ENOENT) {
+ dbg_tnc("found 0, lvl %d, n -1", znode->level);
+ *n = -1;
+ return 0;
+ }
+ if (unlikely(err < 0))
+ return err;
+ if (keys_cmp(c, key, &znode->zbranch[*n].key)) {
+ dbg_tnc("found 0, lvl %d, n -1", znode->level);
+ *n = -1;
+ return 0;
+ }
+
+ dbg_tnc("found 1, lvl %d, n %d", znode->level, *n);
+ *zn = znode;
+ return 1;
+}
+
+/**
+ * lookup_level0_dirty - search for zero-level znode dirtying.
+ * @c: UBIFS file-system description object
+ * @key: key to lookup
+ * @zn: znode is returned here
+ * @n: znode branch slot number is returned here
+ *
+ * This function looks up the TNC tree and search for zero-level znode which
+ * refers key @key. The found zero-level znode is returned in @zn. There are 3
+ * cases:
+ * o exact match, i.e. the found zero-level znode contains key @key, then %1
+ * is returned and slot number of the matched branch is stored in @n;
+ * o not exact match, which means that zero-level znode does not contain @key
+ * then %0 is returned and slot number of the closed branch is stored in
+ * @n;
+ * o @key is so small that it is even less than the lowest key of the
+ * leftmost zero-level node, then %0 is returned and %-1 is stored in @n.
+ *
+ * Additionally all znodes in the path from the root to the located zero-level
+ * znode are marked as dirty.
+ *
+ * Note, when the TNC tree is traversed, some znodes may be absent, then this
+ * function reads corresponding indexing nodes and inserts them to TNC. In
+ * case of failure, a negative error code is returned.
+ */
+static int lookup_level0_dirty(struct ubifs_info *c, const union ubifs_key *key,
+ struct ubifs_znode **zn, int *n)
+{
+ int err, exact;
+ struct ubifs_znode *znode;
+ unsigned long time = get_seconds();
+
+ dbg_tnc("search and dirty key %s", DBGKEY(key));
+
+ znode = c->zroot.znode;
+ if (unlikely(!znode)) {
+ znode = ubifs_load_znode(c, &c->zroot, NULL, 0);
+ if (IS_ERR(znode))
+ return PTR_ERR(znode);
+ }
+
+ znode = dirty_cow_znode(c, &c->zroot);
+ if (IS_ERR(znode))
+ return PTR_ERR(znode);
+
+ znode->time = time;
+
+ while (1) {
+ struct ubifs_zbranch *zbr;
+
+ exact = ubifs_search_zbranch(c, znode, key, n);
+
+ if (znode->level == 0)
+ break;
+
+ if (*n < 0)
+ *n = 0;
+ zbr = &znode->zbranch[*n];
+
+ if (zbr->znode) {
+ znode->time = time;
+ znode = dirty_cow_znode(c, zbr);
+ if (IS_ERR(znode))
+ return PTR_ERR(znode);
+ continue;
+ }
+
+ /* znode is not in TNC cache, load it from the media */
+ znode = ubifs_load_znode(c, zbr, znode, *n);
+ if (IS_ERR(znode))
+ return PTR_ERR(znode);
+ znode = dirty_cow_znode(c, zbr);
+ if (IS_ERR(znode))
+ return PTR_ERR(znode);
+ }
+
+ *zn = znode;
+ if (exact || !is_hash_key(c, key) || *n != -1) {
+ dbg_tnc("found %d, lvl %d, n %d", exact, znode->level, *n);
+ return exact;
+ }
+
+ /*
+ * See huge comment at 'lookup_level0_dirty()' what is the rest of the
+ * code.
+ */
+ err = tnc_prev(c, &znode, n);
+ if (err == -ENOENT) {
+ *n = -1;
+ dbg_tnc("found 0, lvl %d, n -1", znode->level);
+ return 0;
+ }
+ if (unlikely(err < 0))
+ return err;
+ if (keys_cmp(c, key, &znode->zbranch[*n].key)) {
+ *n = -1;
+ dbg_tnc("found 0, lvl %d, n -1", znode->level);
+ return 0;
+ }
+
+ if (znode->cnext || !ubifs_zn_dirty(znode)) {
+ znode = dirty_cow_bottom_up(c, znode);
+ if (IS_ERR(znode))
+ return PTR_ERR(znode);
+ }
+
+ dbg_tnc("found 1, lvl %d, n %d", znode->level, *n);
+ *zn = znode;
+ return 1;
+}
+
+/**
+ * maybe_leb_gced - determine if a LEB may have been garbage collected.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number
+ * @gc_seq1: garbage collection sequence number
+ *
+ * This function determines if @lnum may have been garbage collected since
+ * sequence number @gc_seq1. If it may have been then %1 is returned, otherwise
+ * %0 is returned.
+ */
+static int maybe_leb_gced(struct ubifs_info *c, int lnum, int gc_seq1)
+{
+ /*
+ * No garbage collection in the read-only U-Boot implementation
+ */
+ return 0;
+}
+
+/**
+ * ubifs_tnc_locate - look up a file-system node and return it and its location.
+ * @c: UBIFS file-system description object
+ * @key: node key to lookup
+ * @node: the node is returned here
+ * @lnum: LEB number is returned here
+ * @offs: offset is returned here
+ *
+ * This function look up and reads node with key @key. The caller has to make
+ * sure the @node buffer is large enough to fit the node. Returns zero in case
+ * of success, %-ENOENT if the node was not found, and a negative error code in
+ * case of failure. The node location can be returned in @lnum and @offs.
+ */
+int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key,
+ void *node, int *lnum, int *offs)
+{
+ int found, n, err, safely = 0, gc_seq1;
+ struct ubifs_znode *znode;
+ struct ubifs_zbranch zbr, *zt;
+
+again:
+ mutex_lock(&c->tnc_mutex);
+ found = ubifs_lookup_level0(c, key, &znode, &n);
+ if (!found) {
+ err = -ENOENT;
+ goto out;
+ } else if (found < 0) {
+ err = found;
+ goto out;
+ }
+ zt = &znode->zbranch[n];
+ if (lnum) {
+ *lnum = zt->lnum;
+ *offs = zt->offs;
+ }
+ if (is_hash_key(c, key)) {
+ /*
+ * In this case the leaf node cache gets used, so we pass the
+ * address of the zbranch and keep the mutex locked
+ */
+ err = tnc_read_node_nm(c, zt, node);
+ goto out;
+ }
+ if (safely) {
+ err = ubifs_tnc_read_node(c, zt, node);
+ goto out;
+ }
+ /* Drop the TNC mutex prematurely and race with garbage collection */
+ zbr = znode->zbranch[n];
+ gc_seq1 = c->gc_seq;
+ mutex_unlock(&c->tnc_mutex);
+
+ err = fallible_read_node(c, key, &zbr, node);
+ if (err <= 0 || maybe_leb_gced(c, zbr.lnum, gc_seq1)) {
+ /*
+ * The node may have been GC'ed out from under us so try again
+ * while keeping the TNC mutex locked.
+ */
+ safely = 1;
+ goto again;
+ }
+ return 0;
+
+out:
+ mutex_unlock(&c->tnc_mutex);
+ return err;
+}
+
+/**
+ * ubifs_tnc_get_bu_keys - lookup keys for bulk-read.
+ * @c: UBIFS file-system description object
+ * @bu: bulk-read parameters and results
+ *
+ * Lookup consecutive data node keys for the same inode that reside
+ * consecutively in the same LEB. This function returns zero in case of success
+ * and a negative error code in case of failure.
+ *
+ * Note, if the bulk-read buffer length (@bu->buf_len) is known, this function
+ * makes sure bulk-read nodes fit the buffer. Otherwise, this function prepares
+ * maximum possible amount of nodes for bulk-read.
+ */
+int ubifs_tnc_get_bu_keys(struct ubifs_info *c, struct bu_info *bu)
+{
+ int n, err = 0, lnum = -1, uninitialized_var(offs);
+ int uninitialized_var(len);
+ unsigned int block = key_block(c, &bu->key);
+ struct ubifs_znode *znode;
+
+ bu->cnt = 0;
+ bu->blk_cnt = 0;
+ bu->eof = 0;
+
+ mutex_lock(&c->tnc_mutex);
+ /* Find first key */
+ err = ubifs_lookup_level0(c, &bu->key, &znode, &n);
+ if (err < 0)
+ goto out;
+ if (err) {
+ /* Key found */
+ len = znode->zbranch[n].len;
+ /* The buffer must be big enough for at least 1 node */
+ if (len > bu->buf_len) {
+ err = -EINVAL;
+ goto out;
+ }
+ /* Add this key */
+ bu->zbranch[bu->cnt++] = znode->zbranch[n];
+ bu->blk_cnt += 1;
+ lnum = znode->zbranch[n].lnum;
+ offs = ALIGN(znode->zbranch[n].offs + len, 8);
+ }
+ while (1) {
+ struct ubifs_zbranch *zbr;
+ union ubifs_key *key;
+ unsigned int next_block;
+
+ /* Find next key */
+ err = tnc_next(c, &znode, &n);
+ if (err)
+ goto out;
+ zbr = &znode->zbranch[n];
+ key = &zbr->key;
+ /* See if there is another data key for this file */
+ if (key_inum(c, key) != key_inum(c, &bu->key) ||
+ key_type(c, key) != UBIFS_DATA_KEY) {
+ err = -ENOENT;
+ goto out;
+ }
+ if (lnum < 0) {
+ /* First key found */
+ lnum = zbr->lnum;
+ offs = ALIGN(zbr->offs + zbr->len, 8);
+ len = zbr->len;
+ if (len > bu->buf_len) {
+ err = -EINVAL;
+ goto out;
+ }
+ } else {
+ /*
+ * The data nodes must be in consecutive positions in
+ * the same LEB.
+ */
+ if (zbr->lnum != lnum || zbr->offs != offs)
+ goto out;
+ offs += ALIGN(zbr->len, 8);
+ len = ALIGN(len, 8) + zbr->len;
+ /* Must not exceed buffer length */
+ if (len > bu->buf_len)
+ goto out;
+ }
+ /* Allow for holes */
+ next_block = key_block(c, key);
+ bu->blk_cnt += (next_block - block - 1);
+ if (bu->blk_cnt >= UBIFS_MAX_BULK_READ)
+ goto out;
+ block = next_block;
+ /* Add this key */
+ bu->zbranch[bu->cnt++] = *zbr;
+ bu->blk_cnt += 1;
+ /* See if we have room for more */
+ if (bu->cnt >= UBIFS_MAX_BULK_READ)
+ goto out;
+ if (bu->blk_cnt >= UBIFS_MAX_BULK_READ)
+ goto out;
+ }
+out:
+ if (err == -ENOENT) {
+ bu->eof = 1;
+ err = 0;
+ }
+ bu->gc_seq = c->gc_seq;
+ mutex_unlock(&c->tnc_mutex);
+ if (err)
+ return err;
+ /*
+ * An enormous hole could cause bulk-read to encompass too many
+ * page cache pages, so limit the number here.
+ */
+ if (bu->blk_cnt > UBIFS_MAX_BULK_READ)
+ bu->blk_cnt = UBIFS_MAX_BULK_READ;
+ /*
+ * Ensure that bulk-read covers a whole number of page cache
+ * pages.
+ */
+ if (UBIFS_BLOCKS_PER_PAGE == 1 ||
+ !(bu->blk_cnt & (UBIFS_BLOCKS_PER_PAGE - 1)))
+ return 0;
+ if (bu->eof) {
+ /* At the end of file we can round up */
+ bu->blk_cnt += UBIFS_BLOCKS_PER_PAGE - 1;
+ return 0;
+ }
+ /* Exclude data nodes that do not make up a whole page cache page */
+ block = key_block(c, &bu->key) + bu->blk_cnt;
+ block &= ~(UBIFS_BLOCKS_PER_PAGE - 1);
+ while (bu->cnt) {
+ if (key_block(c, &bu->zbranch[bu->cnt - 1].key) < block)
+ break;
+ bu->cnt -= 1;
+ }
+ return 0;
+}
+
+/**
+ * validate_data_node - validate data nodes for bulk-read.
+ * @c: UBIFS file-system description object
+ * @buf: buffer containing data node to validate
+ * @zbr: zbranch of data node to validate
+ *
+ * This functions returns %0 on success or a negative error code on failure.
+ */
+static int validate_data_node(struct ubifs_info *c, void *buf,
+ struct ubifs_zbranch *zbr)
+{
+ union ubifs_key key1;
+ struct ubifs_ch *ch = buf;
+ int err, len;
+
+ if (ch->node_type != UBIFS_DATA_NODE) {
+ ubifs_err("bad node type (%d but expected %d)",
+ ch->node_type, UBIFS_DATA_NODE);
+ goto out_err;
+ }
+
+ err = ubifs_check_node(c, buf, zbr->lnum, zbr->offs, 0, 0);
+ if (err) {
+ ubifs_err("expected node type %d", UBIFS_DATA_NODE);
+ goto out;
+ }
+
+ len = le32_to_cpu(ch->len);
+ if (len != zbr->len) {
+ ubifs_err("bad node length %d, expected %d", len, zbr->len);
+ goto out_err;
+ }
+
+ /* Make sure the key of the read node is correct */
+ key_read(c, buf + UBIFS_KEY_OFFSET, &key1);
+ if (!keys_eq(c, &zbr->key, &key1)) {
+ ubifs_err("bad key in node at LEB %d:%d",
+ zbr->lnum, zbr->offs);
+ dbg_tnc("looked for key %s found node's key %s",
+ DBGKEY(&zbr->key), DBGKEY1(&key1));
+ goto out_err;
+ }
+
+ return 0;
+
+out_err:
+ err = -EINVAL;
+out:
+ ubifs_err("bad node at LEB %d:%d", zbr->lnum, zbr->offs);
+ dbg_dump_node(c, buf);
+ dbg_dump_stack();
+ return err;
+}
+
+/**
+ * ubifs_tnc_bulk_read - read a number of data nodes in one go.
+ * @c: UBIFS file-system description object
+ * @bu: bulk-read parameters and results
+ *
+ * This functions reads and validates the data nodes that were identified by the
+ * 'ubifs_tnc_get_bu_keys()' function. This functions returns %0 on success,
+ * -EAGAIN to indicate a race with GC, or another negative error code on
+ * failure.
+ */
+int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu)
+{
+ int lnum = bu->zbranch[0].lnum, offs = bu->zbranch[0].offs, len, err, i;
+ void *buf;
+
+ len = bu->zbranch[bu->cnt - 1].offs;
+ len += bu->zbranch[bu->cnt - 1].len - offs;
+ if (len > bu->buf_len) {
+ ubifs_err("buffer too small %d vs %d", bu->buf_len, len);
+ return -EINVAL;
+ }
+
+ /* Do the read */
+ err = ubi_read(c->ubi, lnum, bu->buf, offs, len);
+
+ /* Check for a race with GC */
+ if (maybe_leb_gced(c, lnum, bu->gc_seq))
+ return -EAGAIN;
+
+ if (err && err != -EBADMSG) {
+ ubifs_err("failed to read from LEB %d:%d, error %d",
+ lnum, offs, err);
+ dbg_dump_stack();
+ dbg_tnc("key %s", DBGKEY(&bu->key));
+ return err;
+ }
+
+ /* Validate the nodes read */
+ buf = bu->buf;
+ for (i = 0; i < bu->cnt; i++) {
+ err = validate_data_node(c, buf, &bu->zbranch[i]);
+ if (err)
+ return err;
+ buf = buf + ALIGN(bu->zbranch[i].len, 8);
+ }
+
+ return 0;
+}
+
+/**
+ * do_lookup_nm- look up a "hashed" node.
+ * @c: UBIFS file-system description object
+ * @key: node key to lookup
+ * @node: the node is returned here
+ * @nm: node name
+ *
+ * This function look up and reads a node which contains name hash in the key.
+ * Since the hash may have collisions, there may be many nodes with the same
+ * key, so we have to sequentially look to all of them until the needed one is
+ * found. This function returns zero in case of success, %-ENOENT if the node
+ * was not found, and a negative error code in case of failure.
+ */
+static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
+ void *node, const struct qstr *nm)
+{
+ int found, n, err;
+ struct ubifs_znode *znode;
+
+ dbg_tnc("name '%.*s' key %s", nm->len, nm->name, DBGKEY(key));
+ mutex_lock(&c->tnc_mutex);
+ found = ubifs_lookup_level0(c, key, &znode, &n);
+ if (!found) {
+ err = -ENOENT;
+ goto out_unlock;
+ } else if (found < 0) {
+ err = found;
+ goto out_unlock;
+ }
+
+ ubifs_assert(n >= 0);
+
+ err = resolve_collision(c, key, &znode, &n, nm);
+ dbg_tnc("rc returned %d, znode %p, n %d", err, znode, n);
+ if (unlikely(err < 0))
+ goto out_unlock;
+ if (err == 0) {
+ err = -ENOENT;
+ goto out_unlock;
+ }
+
+ err = tnc_read_node_nm(c, &znode->zbranch[n], node);
+
+out_unlock:
+ mutex_unlock(&c->tnc_mutex);
+ return err;
+}
+
+/**
+ * ubifs_tnc_lookup_nm - look up a "hashed" node.
+ * @c: UBIFS file-system description object
+ * @key: node key to lookup
+ * @node: the node is returned here
+ * @nm: node name
+ *
+ * This function look up and reads a node which contains name hash in the key.
+ * Since the hash may have collisions, there may be many nodes with the same
+ * key, so we have to sequentially look to all of them until the needed one is
+ * found. This function returns zero in case of success, %-ENOENT if the node
+ * was not found, and a negative error code in case of failure.
+ */
+int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
+ void *node, const struct qstr *nm)
+{
+ int err, len;
+ const struct ubifs_dent_node *dent = node;
+
+ /*
+ * We assume that in most of the cases there are no name collisions and
+ * 'ubifs_tnc_lookup()' returns us the right direntry.
+ */
+ err = ubifs_tnc_lookup(c, key, node);
+ if (err)
+ return err;
+
+ len = le16_to_cpu(dent->nlen);
+ if (nm->len == len && !memcmp(dent->name, nm->name, len))
+ return 0;
+
+ /*
+ * Unluckily, there are hash collisions and we have to iterate over
+ * them look at each direntry with colliding name hash sequentially.
+ */
+ return do_lookup_nm(c, key, node, nm);
+}
+
+/**
+ * correct_parent_keys - correct parent znodes' keys.
+ * @c: UBIFS file-system description object
+ * @znode: znode to correct parent znodes for
+ *
+ * This is a helper function for 'tnc_insert()'. When the key of the leftmost
+ * zbranch changes, keys of parent znodes have to be corrected. This helper
+ * function is called in such situations and corrects the keys if needed.
+ */
+static void correct_parent_keys(const struct ubifs_info *c,
+ struct ubifs_znode *znode)
+{
+ union ubifs_key *key, *key1;
+
+ ubifs_assert(znode->parent);
+ ubifs_assert(znode->iip == 0);
+
+ key = &znode->zbranch[0].key;
+ key1 = &znode->parent->zbranch[0].key;
+
+ while (keys_cmp(c, key, key1) < 0) {
+ key_copy(c, key, key1);
+ znode = znode->parent;
+ znode->alt = 1;
+ if (!znode->parent || znode->iip)
+ break;
+ key1 = &znode->parent->zbranch[0].key;
+ }
+}
+
+/**
+ * insert_zbranch - insert a zbranch into a znode.
+ * @znode: znode into which to insert
+ * @zbr: zbranch to insert
+ * @n: slot number to insert to
+ *
+ * This is a helper function for 'tnc_insert()'. UBIFS does not allow "gaps" in
+ * znode's array of zbranches and keeps zbranches consolidated, so when a new
+ * zbranch has to be inserted to the @znode->zbranches[]' array at the @n-th
+ * slot, zbranches starting from @n have to be moved right.
+ */
+static void insert_zbranch(struct ubifs_znode *znode,
+ const struct ubifs_zbranch *zbr, int n)
+{
+ int i;
+
+ ubifs_assert(ubifs_zn_dirty(znode));
+
+ if (znode->level) {
+ for (i = znode->child_cnt; i > n; i--) {
+ znode->zbranch[i] = znode->zbranch[i - 1];
+ if (znode->zbranch[i].znode)
+ znode->zbranch[i].znode->iip = i;
+ }
+ if (zbr->znode)
+ zbr->znode->iip = n;
+ } else
+ for (i = znode->child_cnt; i > n; i--)
+ znode->zbranch[i] = znode->zbranch[i - 1];
+
+ znode->zbranch[n] = *zbr;
+ znode->child_cnt += 1;
+
+ /*
+ * After inserting at slot zero, the lower bound of the key range of
+ * this znode may have changed. If this znode is subsequently split
+ * then the upper bound of the key range may change, and furthermore
+ * it could change to be lower than the original lower bound. If that
+ * happens, then it will no longer be possible to find this znode in the
+ * TNC using the key from the index node on flash. That is bad because
+ * if it is not found, we will assume it is obsolete and may overwrite
+ * it. Then if there is an unclean unmount, we will start using the
+ * old index which will be broken.
+ *
+ * So we first mark znodes that have insertions at slot zero, and then
+ * if they are split we add their lnum/offs to the old_idx tree.
+ */
+ if (n == 0)
+ znode->alt = 1;
+}
+
+/**
+ * tnc_insert - insert a node into TNC.
+ * @c: UBIFS file-system description object
+ * @znode: znode to insert into
+ * @zbr: branch to insert
+ * @n: slot number to insert new zbranch to
+ *
+ * This function inserts a new node described by @zbr into znode @znode. If
+ * znode does not have a free slot for new zbranch, it is split. Parent znodes
+ * are splat as well if needed. Returns zero in case of success or a negative
+ * error code in case of failure.
+ */
+static int tnc_insert(struct ubifs_info *c, struct ubifs_znode *znode,
+ struct ubifs_zbranch *zbr, int n)
+{
+ struct ubifs_znode *zn, *zi, *zp;
+ int i, keep, move, appending = 0;
+ union ubifs_key *key = &zbr->key, *key1;
+
+ ubifs_assert(n >= 0 && n <= c->fanout);
+
+ /* Implement naive insert for now */
+again:
+ zp = znode->parent;
+ if (znode->child_cnt < c->fanout) {
+ ubifs_assert(n != c->fanout);
+ dbg_tnc("inserted at %d level %d, key %s", n, znode->level,
+ DBGKEY(key));
+
+ insert_zbranch(znode, zbr, n);
+
+ /* Ensure parent's key is correct */
+ if (n == 0 && zp && znode->iip == 0)
+ correct_parent_keys(c, znode);
+
+ return 0;
+ }
+
+ /*
+ * Unfortunately, @znode does not have more empty slots and we have to
+ * split it.
+ */
+ dbg_tnc("splitting level %d, key %s", znode->level, DBGKEY(key));
+
+ if (znode->alt)
+ /*
+ * We can no longer be sure of finding this znode by key, so we
+ * record it in the old_idx tree.
+ */
+ ins_clr_old_idx_znode(c, znode);
+
+ zn = kzalloc(c->max_znode_sz, GFP_NOFS);
+ if (!zn)
+ return -ENOMEM;
+ zn->parent = zp;
+ zn->level = znode->level;
+
+ /* Decide where to split */
+ if (znode->level == 0 && key_type(c, key) == UBIFS_DATA_KEY) {
+ /* Try not to split consecutive data keys */
+ if (n == c->fanout) {
+ key1 = &znode->zbranch[n - 1].key;
+ if (key_inum(c, key1) == key_inum(c, key) &&
+ key_type(c, key1) == UBIFS_DATA_KEY)
+ appending = 1;
+ } else
+ goto check_split;
+ } else if (appending && n != c->fanout) {
+ /* Try not to split consecutive data keys */
+ appending = 0;
+check_split:
+ if (n >= (c->fanout + 1) / 2) {
+ key1 = &znode->zbranch[0].key;
+ if (key_inum(c, key1) == key_inum(c, key) &&
+ key_type(c, key1) == UBIFS_DATA_KEY) {
+ key1 = &znode->zbranch[n].key;
+ if (key_inum(c, key1) != key_inum(c, key) ||
+ key_type(c, key1) != UBIFS_DATA_KEY) {
+ keep = n;
+ move = c->fanout - keep;
+ zi = znode;
+ goto do_split;
+ }
+ }
+ }
+ }
+
+ if (appending) {
+ keep = c->fanout;
+ move = 0;
+ } else {
+ keep = (c->fanout + 1) / 2;
+ move = c->fanout - keep;
+ }
+
+ /*
+ * Although we don't at present, we could look at the neighbors and see
+ * if we can move some zbranches there.
+ */
+
+ if (n < keep) {
+ /* Insert into existing znode */
+ zi = znode;
+ move += 1;
+ keep -= 1;
+ } else {
+ /* Insert into new znode */
+ zi = zn;
+ n -= keep;
+ /* Re-parent */
+ if (zn->level != 0)
+ zbr->znode->parent = zn;
+ }
+
+do_split:
+
+ __set_bit(DIRTY_ZNODE, &zn->flags);
+ atomic_long_inc(&c->dirty_zn_cnt);
+
+ zn->child_cnt = move;
+ znode->child_cnt = keep;
+
+ dbg_tnc("moving %d, keeping %d", move, keep);
+
+ /* Move zbranch */
+ for (i = 0; i < move; i++) {
+ zn->zbranch[i] = znode->zbranch[keep + i];
+ /* Re-parent */
+ if (zn->level != 0)
+ if (zn->zbranch[i].znode) {
+ zn->zbranch[i].znode->parent = zn;
+ zn->zbranch[i].znode->iip = i;
+ }
+ }
+
+ /* Insert new key and branch */
+ dbg_tnc("inserting at %d level %d, key %s", n, zn->level, DBGKEY(key));
+
+ insert_zbranch(zi, zbr, n);
+
+ /* Insert new znode (produced by spitting) into the parent */
+ if (zp) {
+ if (n == 0 && zi == znode && znode->iip == 0)
+ correct_parent_keys(c, znode);
+
+ /* Locate insertion point */
+ n = znode->iip + 1;
+
+ /* Tail recursion */
+ zbr->key = zn->zbranch[0].key;
+ zbr->znode = zn;
+ zbr->lnum = 0;
+ zbr->offs = 0;
+ zbr->len = 0;
+ znode = zp;
+
+ goto again;
+ }
+
+ /* We have to split root znode */
+ dbg_tnc("creating new zroot at level %d", znode->level + 1);
+
+ zi = kzalloc(c->max_znode_sz, GFP_NOFS);
+ if (!zi)
+ return -ENOMEM;
+
+ zi->child_cnt = 2;
+ zi->level = znode->level + 1;
+
+ __set_bit(DIRTY_ZNODE, &zi->flags);
+ atomic_long_inc(&c->dirty_zn_cnt);
+
+ zi->zbranch[0].key = znode->zbranch[0].key;
+ zi->zbranch[0].znode = znode;
+ zi->zbranch[0].lnum = c->zroot.lnum;
+ zi->zbranch[0].offs = c->zroot.offs;
+ zi->zbranch[0].len = c->zroot.len;
+ zi->zbranch[1].key = zn->zbranch[0].key;
+ zi->zbranch[1].znode = zn;
+
+ c->zroot.lnum = 0;
+ c->zroot.offs = 0;
+ c->zroot.len = 0;
+ c->zroot.znode = zi;
+
+ zn->parent = zi;
+ zn->iip = 1;
+ znode->parent = zi;
+ znode->iip = 0;
+
+ return 0;
+}
+
+/**
+ * ubifs_tnc_add - add a node to TNC.
+ * @c: UBIFS file-system description object
+ * @key: key to add
+ * @lnum: LEB number of node
+ * @offs: node offset
+ * @len: node length
+ *
+ * This function adds a node with key @key to TNC. The node may be new or it may
+ * obsolete some existing one. Returns %0 on success or negative error code on
+ * failure.
+ */
+int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
+ int offs, int len)
+{
+ int found, n, err = 0;
+ struct ubifs_znode *znode;
+
+ mutex_lock(&c->tnc_mutex);
+ dbg_tnc("%d:%d, len %d, key %s", lnum, offs, len, DBGKEY(key));
+ found = lookup_level0_dirty(c, key, &znode, &n);
+ if (!found) {
+ struct ubifs_zbranch zbr;
+
+ zbr.znode = NULL;
+ zbr.lnum = lnum;
+ zbr.offs = offs;
+ zbr.len = len;
+ key_copy(c, key, &zbr.key);
+ err = tnc_insert(c, znode, &zbr, n + 1);
+ } else if (found == 1) {
+ struct ubifs_zbranch *zbr = &znode->zbranch[n];
+
+ lnc_free(zbr);
+ err = ubifs_add_dirt(c, zbr->lnum, zbr->len);
+ zbr->lnum = lnum;
+ zbr->offs = offs;
+ zbr->len = len;
+ } else
+ err = found;
+ if (!err)
+ err = dbg_check_tnc(c, 0);
+ mutex_unlock(&c->tnc_mutex);
+
+ return err;
+}
+
+/**
+ * ubifs_tnc_replace - replace a node in the TNC only if the old node is found.
+ * @c: UBIFS file-system description object
+ * @key: key to add
+ * @old_lnum: LEB number of old node
+ * @old_offs: old node offset
+ * @lnum: LEB number of node
+ * @offs: node offset
+ * @len: node length
+ *
+ * This function replaces a node with key @key in the TNC only if the old node
+ * is found. This function is called by garbage collection when node are moved.
+ * Returns %0 on success or negative error code on failure.
+ */
+int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
+ int old_lnum, int old_offs, int lnum, int offs, int len)
+{
+ int found, n, err = 0;
+ struct ubifs_znode *znode;
+
+ mutex_lock(&c->tnc_mutex);
+ dbg_tnc("old LEB %d:%d, new LEB %d:%d, len %d, key %s", old_lnum,
+ old_offs, lnum, offs, len, DBGKEY(key));
+ found = lookup_level0_dirty(c, key, &znode, &n);
+ if (found < 0) {
+ err = found;
+ goto out_unlock;
+ }
+
+ if (found == 1) {
+ struct ubifs_zbranch *zbr = &znode->zbranch[n];
+
+ found = 0;
+ if (zbr->lnum == old_lnum && zbr->offs == old_offs) {
+ lnc_free(zbr);
+ err = ubifs_add_dirt(c, zbr->lnum, zbr->len);
+ if (err)
+ goto out_unlock;
+ zbr->lnum = lnum;
+ zbr->offs = offs;
+ zbr->len = len;
+ found = 1;
+ } else if (is_hash_key(c, key)) {
+ found = resolve_collision_directly(c, key, &znode, &n,
+ old_lnum, old_offs);
+ dbg_tnc("rc returned %d, znode %p, n %d, LEB %d:%d",
+ found, znode, n, old_lnum, old_offs);
+ if (found < 0) {
+ err = found;
+ goto out_unlock;
+ }
+
+ if (found) {
+ /* Ensure the znode is dirtied */
+ if (znode->cnext || !ubifs_zn_dirty(znode)) {
+ znode = dirty_cow_bottom_up(c, znode);
+ if (IS_ERR(znode)) {
+ err = PTR_ERR(znode);
+ goto out_unlock;
+ }
+ }
+ zbr = &znode->zbranch[n];
+ lnc_free(zbr);
+ err = ubifs_add_dirt(c, zbr->lnum,
+ zbr->len);
+ if (err)
+ goto out_unlock;
+ zbr->lnum = lnum;
+ zbr->offs = offs;
+ zbr->len = len;
+ }
+ }
+ }
+
+ if (!found)
+ err = ubifs_add_dirt(c, lnum, len);
+
+ if (!err)
+ err = dbg_check_tnc(c, 0);
+
+out_unlock:
+ mutex_unlock(&c->tnc_mutex);
+ return err;
+}
+
+/**
+ * ubifs_tnc_add_nm - add a "hashed" node to TNC.
+ * @c: UBIFS file-system description object
+ * @key: key to add
+ * @lnum: LEB number of node
+ * @offs: node offset
+ * @len: node length
+ * @nm: node name
+ *
+ * This is the same as 'ubifs_tnc_add()' but it should be used with keys which
+ * may have collisions, like directory entry keys.
+ */
+int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
+ int lnum, int offs, int len, const struct qstr *nm)
+{
+ int found, n, err = 0;
+ struct ubifs_znode *znode;
+
+ mutex_lock(&c->tnc_mutex);
+ dbg_tnc("LEB %d:%d, name '%.*s', key %s", lnum, offs, nm->len, nm->name,
+ DBGKEY(key));
+ found = lookup_level0_dirty(c, key, &znode, &n);
+ if (found < 0) {
+ err = found;
+ goto out_unlock;
+ }
+
+ if (found == 1) {
+ if (c->replaying)
+ found = fallible_resolve_collision(c, key, &znode, &n,
+ nm, 1);
+ else
+ found = resolve_collision(c, key, &znode, &n, nm);
+ dbg_tnc("rc returned %d, znode %p, n %d", found, znode, n);
+ if (found < 0) {
+ err = found;
+ goto out_unlock;
+ }
+
+ /* Ensure the znode is dirtied */
+ if (znode->cnext || !ubifs_zn_dirty(znode)) {
+ znode = dirty_cow_bottom_up(c, znode);
+ if (IS_ERR(znode)) {
+ err = PTR_ERR(znode);
+ goto out_unlock;
+ }
+ }
+
+ if (found == 1) {
+ struct ubifs_zbranch *zbr = &znode->zbranch[n];
+
+ lnc_free(zbr);
+ err = ubifs_add_dirt(c, zbr->lnum, zbr->len);
+ zbr->lnum = lnum;
+ zbr->offs = offs;
+ zbr->len = len;
+ goto out_unlock;
+ }
+ }
+
+ if (!found) {
+ struct ubifs_zbranch zbr;
+
+ zbr.znode = NULL;
+ zbr.lnum = lnum;
+ zbr.offs = offs;
+ zbr.len = len;
+ key_copy(c, key, &zbr.key);
+ err = tnc_insert(c, znode, &zbr, n + 1);
+ if (err)
+ goto out_unlock;
+ if (c->replaying) {
+ /*
+ * We did not find it in the index so there may be a
+ * dangling branch still in the index. So we remove it
+ * by passing 'ubifs_tnc_remove_nm()' the same key but
+ * an unmatchable name.
+ */
+ struct qstr noname = { .len = 0, .name = "" };
+
+ err = dbg_check_tnc(c, 0);
+ mutex_unlock(&c->tnc_mutex);
+ if (err)
+ return err;
+ return ubifs_tnc_remove_nm(c, key, &noname);
+ }
+ }
+
+out_unlock:
+ if (!err)
+ err = dbg_check_tnc(c, 0);
+ mutex_unlock(&c->tnc_mutex);
+ return err;
+}
+
+/**
+ * tnc_delete - delete a znode form TNC.
+ * @c: UBIFS file-system description object
+ * @znode: znode to delete from
+ * @n: zbranch slot number to delete
+ *
+ * This function deletes a leaf node from @n-th slot of @znode. Returns zero in
+ * case of success and a negative error code in case of failure.
+ */
+static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
+{
+ struct ubifs_zbranch *zbr;
+ struct ubifs_znode *zp;
+ int i, err;
+
+ /* Delete without merge for now */
+ ubifs_assert(znode->level == 0);
+ ubifs_assert(n >= 0 && n < c->fanout);
+ dbg_tnc("deleting %s", DBGKEY(&znode->zbranch[n].key));
+
+ zbr = &znode->zbranch[n];
+ lnc_free(zbr);
+
+ err = ubifs_add_dirt(c, zbr->lnum, zbr->len);
+ if (err) {
+ dbg_dump_znode(c, znode);
+ return err;
+ }
+
+ /* We do not "gap" zbranch slots */
+ for (i = n; i < znode->child_cnt - 1; i++)
+ znode->zbranch[i] = znode->zbranch[i + 1];
+ znode->child_cnt -= 1;
+
+ if (znode->child_cnt > 0)
+ return 0;
+
+ /*
+ * This was the last zbranch, we have to delete this znode from the
+ * parent.
+ */
+
+ do {
+ ubifs_assert(!test_bit(OBSOLETE_ZNODE, &znode->flags));
+ ubifs_assert(ubifs_zn_dirty(znode));
+
+ zp = znode->parent;
+ n = znode->iip;
+
+ atomic_long_dec(&c->dirty_zn_cnt);
+
+ err = insert_old_idx_znode(c, znode);
+ if (err)
+ return err;
+
+ if (znode->cnext) {
+ __set_bit(OBSOLETE_ZNODE, &znode->flags);
+ atomic_long_inc(&c->clean_zn_cnt);
+ atomic_long_inc(&ubifs_clean_zn_cnt);
+ } else
+ kfree(znode);
+ znode = zp;
+ } while (znode->child_cnt == 1); /* while removing last child */
+
+ /* Remove from znode, entry n - 1 */
+ znode->child_cnt -= 1;
+ ubifs_assert(znode->level != 0);
+ for (i = n; i < znode->child_cnt; i++) {
+ znode->zbranch[i] = znode->zbranch[i + 1];
+ if (znode->zbranch[i].znode)
+ znode->zbranch[i].znode->iip = i;
+ }
+
+ /*
+ * If this is the root and it has only 1 child then
+ * collapse the tree.
+ */
+ if (!znode->parent) {
+ while (znode->child_cnt == 1 && znode->level != 0) {
+ zp = znode;
+ zbr = &znode->zbranch[0];
+ znode = get_znode(c, znode, 0);
+ if (IS_ERR(znode))
+ return PTR_ERR(znode);
+ znode = dirty_cow_znode(c, zbr);
+ if (IS_ERR(znode))
+ return PTR_ERR(znode);
+ znode->parent = NULL;
+ znode->iip = 0;
+ if (c->zroot.len) {
+ err = insert_old_idx(c, c->zroot.lnum,
+ c->zroot.offs);
+ if (err)
+ return err;
+ }
+ c->zroot.lnum = zbr->lnum;
+ c->zroot.offs = zbr->offs;
+ c->zroot.len = zbr->len;
+ c->zroot.znode = znode;
+ ubifs_assert(!test_bit(OBSOLETE_ZNODE,
+ &zp->flags));
+ ubifs_assert(test_bit(DIRTY_ZNODE, &zp->flags));
+ atomic_long_dec(&c->dirty_zn_cnt);
+
+ if (zp->cnext) {
+ __set_bit(OBSOLETE_ZNODE, &zp->flags);
+ atomic_long_inc(&c->clean_zn_cnt);
+ atomic_long_inc(&ubifs_clean_zn_cnt);
+ } else
+ kfree(zp);
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * ubifs_tnc_remove - remove an index entry of a node.
+ * @c: UBIFS file-system description object
+ * @key: key of node
+ *
+ * Returns %0 on success or negative error code on failure.
+ */
+int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key)
+{
+ int found, n, err = 0;
+ struct ubifs_znode *znode;
+
+ mutex_lock(&c->tnc_mutex);
+ dbg_tnc("key %s", DBGKEY(key));
+ found = lookup_level0_dirty(c, key, &znode, &n);
+ if (found < 0) {
+ err = found;
+ goto out_unlock;
+ }
+ if (found == 1)
+ err = tnc_delete(c, znode, n);
+ if (!err)
+ err = dbg_check_tnc(c, 0);
+
+out_unlock:
+ mutex_unlock(&c->tnc_mutex);
+ return err;
+}
+
+/**
+ * ubifs_tnc_remove_nm - remove an index entry for a "hashed" node.
+ * @c: UBIFS file-system description object
+ * @key: key of node
+ * @nm: directory entry name
+ *
+ * Returns %0 on success or negative error code on failure.
+ */
+int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
+ const struct qstr *nm)
+{
+ int n, err;
+ struct ubifs_znode *znode;
+
+ mutex_lock(&c->tnc_mutex);
+ dbg_tnc("%.*s, key %s", nm->len, nm->name, DBGKEY(key));
+ err = lookup_level0_dirty(c, key, &znode, &n);
+ if (err < 0)
+ goto out_unlock;
+
+ if (err) {
+ if (c->replaying)
+ err = fallible_resolve_collision(c, key, &znode, &n,
+ nm, 0);
+ else
+ err = resolve_collision(c, key, &znode, &n, nm);
+ dbg_tnc("rc returned %d, znode %p, n %d", err, znode, n);
+ if (err < 0)
+ goto out_unlock;
+ if (err) {
+ /* Ensure the znode is dirtied */
+ if (znode->cnext || !ubifs_zn_dirty(znode)) {
+ znode = dirty_cow_bottom_up(c, znode);
+ if (IS_ERR(znode)) {
+ err = PTR_ERR(znode);
+ goto out_unlock;
+ }
+ }
+ err = tnc_delete(c, znode, n);
+ }
+ }
+
+out_unlock:
+ if (!err)
+ err = dbg_check_tnc(c, 0);
+ mutex_unlock(&c->tnc_mutex);
+ return err;
+}
+
+/**
+ * key_in_range - determine if a key falls within a range of keys.
+ * @c: UBIFS file-system description object
+ * @key: key to check
+ * @from_key: lowest key in range
+ * @to_key: highest key in range
+ *
+ * This function returns %1 if the key is in range and %0 otherwise.
+ */
+static int key_in_range(struct ubifs_info *c, union ubifs_key *key,
+ union ubifs_key *from_key, union ubifs_key *to_key)
+{
+ if (keys_cmp(c, key, from_key) < 0)
+ return 0;
+ if (keys_cmp(c, key, to_key) > 0)
+ return 0;
+ return 1;
+}
+
+/**
+ * ubifs_tnc_remove_range - remove index entries in range.
+ * @c: UBIFS file-system description object
+ * @from_key: lowest key to remove
+ * @to_key: highest key to remove
+ *
+ * This function removes index entries starting at @from_key and ending at
+ * @to_key. This function returns zero in case of success and a negative error
+ * code in case of failure.
+ */
+int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key,
+ union ubifs_key *to_key)
+{
+ int i, n, k, err = 0;
+ struct ubifs_znode *znode;
+ union ubifs_key *key;
+
+ mutex_lock(&c->tnc_mutex);
+ while (1) {
+ /* Find first level 0 znode that contains keys to remove */
+ err = ubifs_lookup_level0(c, from_key, &znode, &n);
+ if (err < 0)
+ goto out_unlock;
+
+ if (err)
+ key = from_key;
+ else {
+ err = tnc_next(c, &znode, &n);
+ if (err == -ENOENT) {
+ err = 0;
+ goto out_unlock;
+ }
+ if (err < 0)
+ goto out_unlock;
+ key = &znode->zbranch[n].key;
+ if (!key_in_range(c, key, from_key, to_key)) {
+ err = 0;
+ goto out_unlock;
+ }
+ }
+
+ /* Ensure the znode is dirtied */
+ if (znode->cnext || !ubifs_zn_dirty(znode)) {
+ znode = dirty_cow_bottom_up(c, znode);
+ if (IS_ERR(znode)) {
+ err = PTR_ERR(znode);
+ goto out_unlock;
+ }
+ }
+
+ /* Remove all keys in range except the first */
+ for (i = n + 1, k = 0; i < znode->child_cnt; i++, k++) {
+ key = &znode->zbranch[i].key;
+ if (!key_in_range(c, key, from_key, to_key))
+ break;
+ lnc_free(&znode->zbranch[i]);
+ err = ubifs_add_dirt(c, znode->zbranch[i].lnum,
+ znode->zbranch[i].len);
+ if (err) {
+ dbg_dump_znode(c, znode);
+ goto out_unlock;
+ }
+ dbg_tnc("removing %s", DBGKEY(key));
+ }
+ if (k) {
+ for (i = n + 1 + k; i < znode->child_cnt; i++)
+ znode->zbranch[i - k] = znode->zbranch[i];
+ znode->child_cnt -= k;
+ }
+
+ /* Now delete the first */
+ err = tnc_delete(c, znode, n);
+ if (err)
+ goto out_unlock;
+ }
+
+out_unlock:
+ if (!err)
+ err = dbg_check_tnc(c, 0);
+ mutex_unlock(&c->tnc_mutex);
+ return err;
+}
+
+/**
+ * ubifs_tnc_remove_ino - remove an inode from TNC.
+ * @c: UBIFS file-system description object
+ * @inum: inode number to remove
+ *
+ * This function remove inode @inum and all the extended attributes associated
+ * with the anode from TNC and returns zero in case of success or a negative
+ * error code in case of failure.
+ */
+int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
+{
+ union ubifs_key key1, key2;
+ struct ubifs_dent_node *xent, *pxent = NULL;
+ struct qstr nm = { .name = NULL };
+
+ dbg_tnc("ino %lu", (unsigned long)inum);
+
+ /*
+ * Walk all extended attribute entries and remove them together with
+ * corresponding extended attribute inodes.
+ */
+ lowest_xent_key(c, &key1, inum);
+ while (1) {
+ ino_t xattr_inum;
+ int err;
+
+ xent = ubifs_tnc_next_ent(c, &key1, &nm);
+ if (IS_ERR(xent)) {
+ err = PTR_ERR(xent);
+ if (err == -ENOENT)
+ break;
+ return err;
+ }
+
+ xattr_inum = le64_to_cpu(xent->inum);
+ dbg_tnc("xent '%s', ino %lu", xent->name,
+ (unsigned long)xattr_inum);
+
+ nm.name = (char *)xent->name;
+ nm.len = le16_to_cpu(xent->nlen);
+ err = ubifs_tnc_remove_nm(c, &key1, &nm);
+ if (err) {
+ kfree(xent);
+ return err;
+ }
+
+ lowest_ino_key(c, &key1, xattr_inum);
+ highest_ino_key(c, &key2, xattr_inum);
+ err = ubifs_tnc_remove_range(c, &key1, &key2);
+ if (err) {
+ kfree(xent);
+ return err;
+ }
+
+ kfree(pxent);
+ pxent = xent;
+ key_read(c, &xent->key, &key1);
+ }
+
+ kfree(pxent);
+ lowest_ino_key(c, &key1, inum);
+ highest_ino_key(c, &key2, inum);
+
+ return ubifs_tnc_remove_range(c, &key1, &key2);
+}
+
+/**
+ * ubifs_tnc_next_ent - walk directory or extended attribute entries.
+ * @c: UBIFS file-system description object
+ * @key: key of last entry
+ * @nm: name of last entry found or %NULL
+ *
+ * This function finds and reads the next directory or extended attribute entry
+ * after the given key (@key) if there is one. @nm is used to resolve
+ * collisions.
+ *
+ * If the name of the current entry is not known and only the key is known,
+ * @nm->name has to be %NULL. In this case the semantics of this function is a
+ * little bit different and it returns the entry corresponding to this key, not
+ * the next one. If the key was not found, the closest "right" entry is
+ * returned.
+ *
+ * If the fist entry has to be found, @key has to contain the lowest possible
+ * key value for this inode and @name has to be %NULL.
+ *
+ * This function returns the found directory or extended attribute entry node
+ * in case of success, %-ENOENT is returned if no entry was found, and a
+ * negative error code is returned in case of failure.
+ */
+struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
+ union ubifs_key *key,
+ const struct qstr *nm)
+{
+ int n, err, type = key_type(c, key);
+ struct ubifs_znode *znode;
+ struct ubifs_dent_node *dent;
+ struct ubifs_zbranch *zbr;
+ union ubifs_key *dkey;
+
+ dbg_tnc("%s %s", nm->name ? (char *)nm->name : "(lowest)", DBGKEY(key));
+ ubifs_assert(is_hash_key(c, key));
+
+ mutex_lock(&c->tnc_mutex);
+ err = ubifs_lookup_level0(c, key, &znode, &n);
+ if (unlikely(err < 0))
+ goto out_unlock;
+
+ if (nm->name) {
+ if (err) {
+ /* Handle collisions */
+ err = resolve_collision(c, key, &znode, &n, nm);
+ dbg_tnc("rc returned %d, znode %p, n %d",
+ err, znode, n);
+ if (unlikely(err < 0))
+ goto out_unlock;
+ }
+
+ /* Now find next entry */
+ err = tnc_next(c, &znode, &n);
+ if (unlikely(err))
+ goto out_unlock;
+ } else {
+ /*
+ * The full name of the entry was not given, in which case the
+ * behavior of this function is a little different and it
+ * returns current entry, not the next one.
+ */
+ if (!err) {
+ /*
+ * However, the given key does not exist in the TNC
+ * tree and @znode/@n variables contain the closest
+ * "preceding" element. Switch to the next one.
+ */
+ err = tnc_next(c, &znode, &n);
+ if (err)
+ goto out_unlock;
+ }
+ }
+
+ zbr = &znode->zbranch[n];
+ dent = kmalloc(zbr->len, GFP_NOFS);
+ if (unlikely(!dent)) {
+ err = -ENOMEM;
+ goto out_unlock;
+ }
+
+ /*
+ * The above 'tnc_next()' call could lead us to the next inode, check
+ * this.
+ */
+ dkey = &zbr->key;
+ if (key_inum(c, dkey) != key_inum(c, key) ||
+ key_type(c, dkey) != type) {
+ err = -ENOENT;
+ goto out_free;
+ }
+
+ err = tnc_read_node_nm(c, zbr, dent);
+ if (unlikely(err))
+ goto out_free;
+
+ mutex_unlock(&c->tnc_mutex);
+ return dent;
+
+out_free:
+ kfree(dent);
+out_unlock:
+ mutex_unlock(&c->tnc_mutex);
+ return ERR_PTR(err);
+}
diff --git a/fs/ubifs/tnc_commit.c b/fs/ubifs/tnc_commit.c
new file mode 100644
index 0000000..8ac76b1
--- /dev/null
+++ b/fs/ubifs/tnc_commit.c
@@ -0,0 +1,1102 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ * Artem Bityutskiy (Битюцкий Ðртём)
+ */
+
+/* This file implements TNC functions for committing */
+
+#include "ubifs.h"
+
+/**
+ * make_idx_node - make an index node for fill-the-gaps method of TNC commit.
+ * @c: UBIFS file-system description object
+ * @idx: buffer in which to place new index node
+ * @znode: znode from which to make new index node
+ * @lnum: LEB number where new index node will be written
+ * @offs: offset where new index node will be written
+ * @len: length of new index node
+ */
+static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
+ struct ubifs_znode *znode, int lnum, int offs, int len)
+{
+ struct ubifs_znode *zp;
+ int i, err;
+
+ /* Make index node */
+ idx->ch.node_type = UBIFS_IDX_NODE;
+ idx->child_cnt = cpu_to_le16(znode->child_cnt);
+ idx->level = cpu_to_le16(znode->level);
+ for (i = 0; i < znode->child_cnt; i++) {
+ struct ubifs_branch *br = ubifs_idx_branch(c, idx, i);
+ struct ubifs_zbranch *zbr = &znode->zbranch[i];
+
+ key_write_idx(c, &zbr->key, &br->key);
+ br->lnum = cpu_to_le32(zbr->lnum);
+ br->offs = cpu_to_le32(zbr->offs);
+ br->len = cpu_to_le32(zbr->len);
+ if (!zbr->lnum || !zbr->len) {
+ ubifs_err("bad ref in znode");
+ dbg_dump_znode(c, znode);
+ if (zbr->znode)
+ dbg_dump_znode(c, zbr->znode);
+ }
+ }
+ ubifs_prepare_node(c, idx, len, 0);
+
+#ifdef CONFIG_UBIFS_FS_DEBUG
+ znode->lnum = lnum;
+ znode->offs = offs;
+ znode->len = len;
+#endif
+
+ err = insert_old_idx_znode(c, znode);
+
+ /* Update the parent */
+ zp = znode->parent;
+ if (zp) {
+ struct ubifs_zbranch *zbr;
+
+ zbr = &zp->zbranch[znode->iip];
+ zbr->lnum = lnum;
+ zbr->offs = offs;
+ zbr->len = len;
+ } else {
+ c->zroot.lnum = lnum;
+ c->zroot.offs = offs;
+ c->zroot.len = len;
+ }
+ c->calc_idx_sz += ALIGN(len, 8);
+
+ atomic_long_dec(&c->dirty_zn_cnt);
+
+ ubifs_assert(ubifs_zn_dirty(znode));
+ ubifs_assert(test_bit(COW_ZNODE, &znode->flags));
+
+ __clear_bit(DIRTY_ZNODE, &znode->flags);
+ __clear_bit(COW_ZNODE, &znode->flags);
+
+ return err;
+}
+
+/**
+ * fill_gap - make index nodes in gaps in dirty index LEBs.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number that gap appears in
+ * @gap_start: offset of start of gap
+ * @gap_end: offset of end of gap
+ * @dirt: adds dirty space to this
+ *
+ * This function returns the number of index nodes written into the gap.
+ */
+static int fill_gap(struct ubifs_info *c, int lnum, int gap_start, int gap_end,
+ int *dirt)
+{
+ int len, gap_remains, gap_pos, written, pad_len;
+
+ ubifs_assert((gap_start & 7) == 0);
+ ubifs_assert((gap_end & 7) == 0);
+ ubifs_assert(gap_end >= gap_start);
+
+ gap_remains = gap_end - gap_start;
+ if (!gap_remains)
+ return 0;
+ gap_pos = gap_start;
+ written = 0;
+ while (c->enext) {
+ len = ubifs_idx_node_sz(c, c->enext->child_cnt);
+ if (len < gap_remains) {
+ struct ubifs_znode *znode = c->enext;
+ const int alen = ALIGN(len, 8);
+ int err;
+
+ ubifs_assert(alen <= gap_remains);
+ err = make_idx_node(c, c->ileb_buf + gap_pos, znode,
+ lnum, gap_pos, len);
+ if (err)
+ return err;
+ gap_remains -= alen;
+ gap_pos += alen;
+ c->enext = znode->cnext;
+ if (c->enext == c->cnext)
+ c->enext = NULL;
+ written += 1;
+ } else
+ break;
+ }
+ if (gap_end == c->leb_size) {
+ c->ileb_len = ALIGN(gap_pos, c->min_io_size);
+ /* Pad to end of min_io_size */
+ pad_len = c->ileb_len - gap_pos;
+ } else
+ /* Pad to end of gap */
+ pad_len = gap_remains;
+ dbg_gc("LEB %d:%d to %d len %d nodes written %d wasted bytes %d",
+ lnum, gap_start, gap_end, gap_end - gap_start, written, pad_len);
+ ubifs_pad(c, c->ileb_buf + gap_pos, pad_len);
+ *dirt += pad_len;
+ return written;
+}
+
+/**
+ * find_old_idx - find an index node obsoleted since the last commit start.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number of obsoleted index node
+ * @offs: offset of obsoleted index node
+ *
+ * Returns %1 if found and %0 otherwise.
+ */
+static int find_old_idx(struct ubifs_info *c, int lnum, int offs)
+{
+ struct ubifs_old_idx *o;
+ struct rb_node *p;
+
+ p = c->old_idx.rb_node;
+ while (p) {
+ o = rb_entry(p, struct ubifs_old_idx, rb);
+ if (lnum < o->lnum)
+ p = p->rb_left;
+ else if (lnum > o->lnum)
+ p = p->rb_right;
+ else if (offs < o->offs)
+ p = p->rb_left;
+ else if (offs > o->offs)
+ p = p->rb_right;
+ else
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * is_idx_node_in_use - determine if an index node can be overwritten.
+ * @c: UBIFS file-system description object
+ * @key: key of index node
+ * @level: index node level
+ * @lnum: LEB number of index node
+ * @offs: offset of index node
+ *
+ * If @key / @lnum / @offs identify an index node that was not part of the old
+ * index, then this function returns %0 (obsolete). Else if the index node was
+ * part of the old index but is now dirty %1 is returned, else if it is clean %2
+ * is returned. A negative error code is returned on failure.
+ */
+static int is_idx_node_in_use(struct ubifs_info *c, union ubifs_key *key,
+ int level, int lnum, int offs)
+{
+ int ret;
+
+ ret = is_idx_node_in_tnc(c, key, level, lnum, offs);
+ if (ret < 0)
+ return ret; /* Error code */
+ if (ret == 0)
+ if (find_old_idx(c, lnum, offs))
+ return 1;
+ return ret;
+}
+
+/**
+ * layout_leb_in_gaps - layout index nodes using in-the-gaps method.
+ * @c: UBIFS file-system description object
+ * @p: return LEB number here
+ *
+ * This function lays out new index nodes for dirty znodes using in-the-gaps
+ * method of TNC commit.
+ * This function merely puts the next znode into the next gap, making no attempt
+ * to try to maximise the number of znodes that fit.
+ * This function returns the number of index nodes written into the gaps, or a
+ * negative error code on failure.
+ */
+static int layout_leb_in_gaps(struct ubifs_info *c, int *p)
+{
+ struct ubifs_scan_leb *sleb;
+ struct ubifs_scan_node *snod;
+ int lnum, dirt = 0, gap_start, gap_end, err, written, tot_written;
+
+ tot_written = 0;
+ /* Get an index LEB with lots of obsolete index nodes */
+ lnum = ubifs_find_dirty_idx_leb(c);
+ if (lnum < 0)
+ /*
+ * There also may be dirt in the index head that could be
+ * filled, however we do not check there at present.
+ */
+ return lnum; /* Error code */
+ *p = lnum;
+ dbg_gc("LEB %d", lnum);
+ /*
+ * Scan the index LEB. We use the generic scan for this even though
+ * it is more comprehensive and less efficient than is needed for this
+ * purpose.
+ */
+ sleb = ubifs_scan(c, lnum, 0, c->ileb_buf);
+ c->ileb_len = 0;
+ if (IS_ERR(sleb))
+ return PTR_ERR(sleb);
+ gap_start = 0;
+ list_for_each_entry(snod, &sleb->nodes, list) {
+ struct ubifs_idx_node *idx;
+ int in_use, level;
+
+ ubifs_assert(snod->type == UBIFS_IDX_NODE);
+ idx = snod->node;
+ key_read(c, ubifs_idx_key(c, idx), &snod->key);
+ level = le16_to_cpu(idx->level);
+ /* Determine if the index node is in use (not obsolete) */
+ in_use = is_idx_node_in_use(c, &snod->key, level, lnum,
+ snod->offs);
+ if (in_use < 0) {
+ ubifs_scan_destroy(sleb);
+ return in_use; /* Error code */
+ }
+ if (in_use) {
+ if (in_use == 1)
+ dirt += ALIGN(snod->len, 8);
+ /*
+ * The obsolete index nodes form gaps that can be
+ * overwritten. This gap has ended because we have
+ * found an index node that is still in use
+ * i.e. not obsolete
+ */
+ gap_end = snod->offs;
+ /* Try to fill gap */
+ written = fill_gap(c, lnum, gap_start, gap_end, &dirt);
+ if (written < 0) {
+ ubifs_scan_destroy(sleb);
+ return written; /* Error code */
+ }
+ tot_written += written;
+ gap_start = ALIGN(snod->offs + snod->len, 8);
+ }
+ }
+ ubifs_scan_destroy(sleb);
+ c->ileb_len = c->leb_size;
+ gap_end = c->leb_size;
+ /* Try to fill gap */
+ written = fill_gap(c, lnum, gap_start, gap_end, &dirt);
+ if (written < 0)
+ return written; /* Error code */
+ tot_written += written;
+ if (tot_written == 0) {
+ struct ubifs_lprops lp;
+
+ dbg_gc("LEB %d wrote %d index nodes", lnum, tot_written);
+ err = ubifs_read_one_lp(c, lnum, &lp);
+ if (err)
+ return err;
+ if (lp.free == c->leb_size) {
+ /*
+ * We must have snatched this LEB from the idx_gc list
+ * so we need to correct the free and dirty space.
+ */
+ err = ubifs_change_one_lp(c, lnum,
+ c->leb_size - c->ileb_len,
+ dirt, 0, 0, 0);
+ if (err)
+ return err;
+ }
+ return 0;
+ }
+ err = ubifs_change_one_lp(c, lnum, c->leb_size - c->ileb_len, dirt,
+ 0, 0, 0);
+ if (err)
+ return err;
+ err = ubifs_leb_change(c, lnum, c->ileb_buf, c->ileb_len,
+ UBI_SHORTTERM);
+ if (err)
+ return err;
+ dbg_gc("LEB %d wrote %d index nodes", lnum, tot_written);
+ return tot_written;
+}
+
+/**
+ * get_leb_cnt - calculate the number of empty LEBs needed to commit.
+ * @c: UBIFS file-system description object
+ * @cnt: number of znodes to commit
+ *
+ * This function returns the number of empty LEBs needed to commit @cnt znodes
+ * to the current index head. The number is not exact and may be more than
+ * needed.
+ */
+static int get_leb_cnt(struct ubifs_info *c, int cnt)
+{
+ int d;
+
+ /* Assume maximum index node size (i.e. overestimate space needed) */
+ cnt -= (c->leb_size - c->ihead_offs) / c->max_idx_node_sz;
+ if (cnt < 0)
+ cnt = 0;
+ d = c->leb_size / c->max_idx_node_sz;
+ return DIV_ROUND_UP(cnt, d);
+}
+
+/**
+ * layout_in_gaps - in-the-gaps method of committing TNC.
+ * @c: UBIFS file-system description object
+ * @cnt: number of dirty znodes to commit.
+ *
+ * This function lays out new index nodes for dirty znodes using in-the-gaps
+ * method of TNC commit.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int layout_in_gaps(struct ubifs_info *c, int cnt)
+{
+ int err, leb_needed_cnt, written, *p;
+
+ dbg_gc("%d znodes to write", cnt);
+
+ c->gap_lebs = kmalloc(sizeof(int) * (c->lst.idx_lebs + 1), GFP_NOFS);
+ if (!c->gap_lebs)
+ return -ENOMEM;
+
+ p = c->gap_lebs;
+ do {
+ ubifs_assert(p < c->gap_lebs + sizeof(int) * c->lst.idx_lebs);
+ written = layout_leb_in_gaps(c, p);
+ if (written < 0) {
+ err = written;
+ if (err != -ENOSPC) {
+ kfree(c->gap_lebs);
+ c->gap_lebs = NULL;
+ return err;
+ }
+ if (!dbg_force_in_the_gaps_enabled) {
+ /*
+ * Do not print scary warnings if the debugging
+ * option which forces in-the-gaps is enabled.
+ */
+ ubifs_err("out of space");
+ spin_lock(&c->space_lock);
+ dbg_dump_budg(c);
+ spin_unlock(&c->space_lock);
+ dbg_dump_lprops(c);
+ }
+ /* Try to commit anyway */
+ err = 0;
+ break;
+ }
+ p++;
+ cnt -= written;
+ leb_needed_cnt = get_leb_cnt(c, cnt);
+ dbg_gc("%d znodes remaining, need %d LEBs, have %d", cnt,
+ leb_needed_cnt, c->ileb_cnt);
+ } while (leb_needed_cnt > c->ileb_cnt);
+
+ *p = -1;
+ return 0;
+}
+
+/**
+ * layout_in_empty_space - layout index nodes in empty space.
+ * @c: UBIFS file-system description object
+ *
+ * This function lays out new index nodes for dirty znodes using empty LEBs.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int layout_in_empty_space(struct ubifs_info *c)
+{
+ struct ubifs_znode *znode, *cnext, *zp;
+ int lnum, offs, len, next_len, buf_len, buf_offs, used, avail;
+ int wlen, blen, err;
+
+ cnext = c->enext;
+ if (!cnext)
+ return 0;
+
+ lnum = c->ihead_lnum;
+ buf_offs = c->ihead_offs;
+
+ buf_len = ubifs_idx_node_sz(c, c->fanout);
+ buf_len = ALIGN(buf_len, c->min_io_size);
+ used = 0;
+ avail = buf_len;
+
+ /* Ensure there is enough room for first write */
+ next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
+ if (buf_offs + next_len > c->leb_size)
+ lnum = -1;
+
+ while (1) {
+ znode = cnext;
+
+ len = ubifs_idx_node_sz(c, znode->child_cnt);
+
+ /* Determine the index node position */
+ if (lnum == -1) {
+ if (c->ileb_nxt >= c->ileb_cnt) {
+ ubifs_err("out of space");
+ return -ENOSPC;
+ }
+ lnum = c->ilebs[c->ileb_nxt++];
+ buf_offs = 0;
+ used = 0;
+ avail = buf_len;
+ }
+
+ offs = buf_offs + used;
+
+#ifdef CONFIG_UBIFS_FS_DEBUG
+ znode->lnum = lnum;
+ znode->offs = offs;
+ znode->len = len;
+#endif
+
+ /* Update the parent */
+ zp = znode->parent;
+ if (zp) {
+ struct ubifs_zbranch *zbr;
+ int i;
+
+ i = znode->iip;
+ zbr = &zp->zbranch[i];
+ zbr->lnum = lnum;
+ zbr->offs = offs;
+ zbr->len = len;
+ } else {
+ c->zroot.lnum = lnum;
+ c->zroot.offs = offs;
+ c->zroot.len = len;
+ }
+ c->calc_idx_sz += ALIGN(len, 8);
+
+ /*
+ * Once lprops is updated, we can decrease the dirty znode count
+ * but it is easier to just do it here.
+ */
+ atomic_long_dec(&c->dirty_zn_cnt);
+
+ /*
+ * Calculate the next index node length to see if there is
+ * enough room for it
+ */
+ cnext = znode->cnext;
+ if (cnext == c->cnext)
+ next_len = 0;
+ else
+ next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
+
+ if (c->min_io_size == 1) {
+ buf_offs += ALIGN(len, 8);
+ if (next_len) {
+ if (buf_offs + next_len <= c->leb_size)
+ continue;
+ err = ubifs_update_one_lp(c, lnum, 0,
+ c->leb_size - buf_offs, 0, 0);
+ if (err)
+ return err;
+ lnum = -1;
+ continue;
+ }
+ err = ubifs_update_one_lp(c, lnum,
+ c->leb_size - buf_offs, 0, 0, 0);
+ if (err)
+ return err;
+ break;
+ }
+
+ /* Update buffer positions */
+ wlen = used + len;
+ used += ALIGN(len, 8);
+ avail -= ALIGN(len, 8);
+
+ if (next_len != 0 &&
+ buf_offs + used + next_len <= c->leb_size &&
+ avail > 0)
+ continue;
+
+ if (avail <= 0 && next_len &&
+ buf_offs + used + next_len <= c->leb_size)
+ blen = buf_len;
+ else
+ blen = ALIGN(wlen, c->min_io_size);
+
+ /* The buffer is full or there are no more znodes to do */
+ buf_offs += blen;
+ if (next_len) {
+ if (buf_offs + next_len > c->leb_size) {
+ err = ubifs_update_one_lp(c, lnum,
+ c->leb_size - buf_offs, blen - used,
+ 0, 0);
+ if (err)
+ return err;
+ lnum = -1;
+ }
+ used -= blen;
+ if (used < 0)
+ used = 0;
+ avail = buf_len - used;
+ continue;
+ }
+ err = ubifs_update_one_lp(c, lnum, c->leb_size - buf_offs,
+ blen - used, 0, 0);
+ if (err)
+ return err;
+ break;
+ }
+
+#ifdef CONFIG_UBIFS_FS_DEBUG
+ c->new_ihead_lnum = lnum;
+ c->new_ihead_offs = buf_offs;
+#endif
+
+ return 0;
+}
+
+/**
+ * layout_commit - determine positions of index nodes to commit.
+ * @c: UBIFS file-system description object
+ * @no_space: indicates that insufficient empty LEBs were allocated
+ * @cnt: number of znodes to commit
+ *
+ * Calculate and update the positions of index nodes to commit. If there were
+ * an insufficient number of empty LEBs allocated, then index nodes are placed
+ * into the gaps created by obsolete index nodes in non-empty index LEBs. For
+ * this purpose, an obsolete index node is one that was not in the index as at
+ * the end of the last commit. To write "in-the-gaps" requires that those index
+ * LEBs are updated atomically in-place.
+ */
+static int layout_commit(struct ubifs_info *c, int no_space, int cnt)
+{
+ int err;
+
+ if (no_space) {
+ err = layout_in_gaps(c, cnt);
+ if (err)
+ return err;
+ }
+ err = layout_in_empty_space(c);
+ return err;
+}
+
+/**
+ * find_first_dirty - find first dirty znode.
+ * @znode: znode to begin searching from
+ */
+static struct ubifs_znode *find_first_dirty(struct ubifs_znode *znode)
+{
+ int i, cont;
+
+ if (!znode)
+ return NULL;
+
+ while (1) {
+ if (znode->level == 0) {
+ if (ubifs_zn_dirty(znode))
+ return znode;
+ return NULL;
+ }
+ cont = 0;
+ for (i = 0; i < znode->child_cnt; i++) {
+ struct ubifs_zbranch *zbr = &znode->zbranch[i];
+
+ if (zbr->znode && ubifs_zn_dirty(zbr->znode)) {
+ znode = zbr->znode;
+ cont = 1;
+ break;
+ }
+ }
+ if (!cont) {
+ if (ubifs_zn_dirty(znode))
+ return znode;
+ return NULL;
+ }
+ }
+}
+
+/**
+ * find_next_dirty - find next dirty znode.
+ * @znode: znode to begin searching from
+ */
+static struct ubifs_znode *find_next_dirty(struct ubifs_znode *znode)
+{
+ int n = znode->iip + 1;
+
+ znode = znode->parent;
+ if (!znode)
+ return NULL;
+ for (; n < znode->child_cnt; n++) {
+ struct ubifs_zbranch *zbr = &znode->zbranch[n];
+
+ if (zbr->znode && ubifs_zn_dirty(zbr->znode))
+ return find_first_dirty(zbr->znode);
+ }
+ return znode;
+}
+
+/**
+ * get_znodes_to_commit - create list of dirty znodes to commit.
+ * @c: UBIFS file-system description object
+ *
+ * This function returns the number of znodes to commit.
+ */
+static int get_znodes_to_commit(struct ubifs_info *c)
+{
+ struct ubifs_znode *znode, *cnext;
+ int cnt = 0;
+
+ c->cnext = find_first_dirty(c->zroot.znode);
+ znode = c->enext = c->cnext;
+ if (!znode) {
+ dbg_cmt("no znodes to commit");
+ return 0;
+ }
+ cnt += 1;
+ while (1) {
+ ubifs_assert(!test_bit(COW_ZNODE, &znode->flags));
+ __set_bit(COW_ZNODE, &znode->flags);
+ znode->alt = 0;
+ cnext = find_next_dirty(znode);
+ if (!cnext) {
+ znode->cnext = c->cnext;
+ break;
+ }
+ znode->cnext = cnext;
+ znode = cnext;
+ cnt += 1;
+ }
+ dbg_cmt("committing %d znodes", cnt);
+ ubifs_assert(cnt == atomic_long_read(&c->dirty_zn_cnt));
+ return cnt;
+}
+
+/**
+ * alloc_idx_lebs - allocate empty LEBs to be used to commit.
+ * @c: UBIFS file-system description object
+ * @cnt: number of znodes to commit
+ *
+ * This function returns %-ENOSPC if it cannot allocate a sufficient number of
+ * empty LEBs. %0 is returned on success, otherwise a negative error code
+ * is returned.
+ */
+static int alloc_idx_lebs(struct ubifs_info *c, int cnt)
+{
+ int i, leb_cnt, lnum;
+
+ c->ileb_cnt = 0;
+ c->ileb_nxt = 0;
+ leb_cnt = get_leb_cnt(c, cnt);
+ dbg_cmt("need about %d empty LEBS for TNC commit", leb_cnt);
+ if (!leb_cnt)
+ return 0;
+ c->ilebs = kmalloc(leb_cnt * sizeof(int), GFP_NOFS);
+ if (!c->ilebs)
+ return -ENOMEM;
+ for (i = 0; i < leb_cnt; i++) {
+ lnum = ubifs_find_free_leb_for_idx(c);
+ if (lnum < 0)
+ return lnum;
+ c->ilebs[c->ileb_cnt++] = lnum;
+ dbg_cmt("LEB %d", lnum);
+ }
+ if (dbg_force_in_the_gaps())
+ return -ENOSPC;
+ return 0;
+}
+
+/**
+ * free_unused_idx_lebs - free unused LEBs that were allocated for the commit.
+ * @c: UBIFS file-system description object
+ *
+ * It is possible that we allocate more empty LEBs for the commit than we need.
+ * This functions frees the surplus.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int free_unused_idx_lebs(struct ubifs_info *c)
+{
+ int i, err = 0, lnum, er;
+
+ for (i = c->ileb_nxt; i < c->ileb_cnt; i++) {
+ lnum = c->ilebs[i];
+ dbg_cmt("LEB %d", lnum);
+ er = ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0,
+ LPROPS_INDEX | LPROPS_TAKEN, 0);
+ if (!err)
+ err = er;
+ }
+ return err;
+}
+
+/**
+ * free_idx_lebs - free unused LEBs after commit end.
+ * @c: UBIFS file-system description object
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int free_idx_lebs(struct ubifs_info *c)
+{
+ int err;
+
+ err = free_unused_idx_lebs(c);
+ kfree(c->ilebs);
+ c->ilebs = NULL;
+ return err;
+}
+
+/**
+ * ubifs_tnc_start_commit - start TNC commit.
+ * @c: UBIFS file-system description object
+ * @zroot: new index root position is returned here
+ *
+ * This function prepares the list of indexing nodes to commit and lays out
+ * their positions on flash. If there is not enough free space it uses the
+ * in-gap commit method. Returns zero in case of success and a negative error
+ * code in case of failure.
+ */
+int ubifs_tnc_start_commit(struct ubifs_info *c, struct ubifs_zbranch *zroot)
+{
+ int err = 0, cnt;
+
+ mutex_lock(&c->tnc_mutex);
+ err = dbg_check_tnc(c, 1);
+ if (err)
+ goto out;
+ cnt = get_znodes_to_commit(c);
+ if (cnt != 0) {
+ int no_space = 0;
+
+ err = alloc_idx_lebs(c, cnt);
+ if (err == -ENOSPC)
+ no_space = 1;
+ else if (err)
+ goto out_free;
+ err = layout_commit(c, no_space, cnt);
+ if (err)
+ goto out_free;
+ ubifs_assert(atomic_long_read(&c->dirty_zn_cnt) == 0);
+ err = free_unused_idx_lebs(c);
+ if (err)
+ goto out;
+ }
+ destroy_old_idx(c);
+ memcpy(zroot, &c->zroot, sizeof(struct ubifs_zbranch));
+
+ err = ubifs_save_dirty_idx_lnums(c);
+ if (err)
+ goto out;
+
+ spin_lock(&c->space_lock);
+ /*
+ * Although we have not finished committing yet, update size of the
+ * committed index ('c->old_idx_sz') and zero out the index growth
+ * budget. It is OK to do this now, because we've reserved all the
+ * space which is needed to commit the index, and it is save for the
+ * budgeting subsystem to assume the index is already committed,
+ * even though it is not.
+ */
+ c->old_idx_sz = c->calc_idx_sz;
+ c->budg_uncommitted_idx = 0;
+ spin_unlock(&c->space_lock);
+ mutex_unlock(&c->tnc_mutex);
+
+ dbg_cmt("number of index LEBs %d", c->lst.idx_lebs);
+ dbg_cmt("size of index %llu", c->calc_idx_sz);
+ return err;
+
+out_free:
+ free_idx_lebs(c);
+out:
+ mutex_unlock(&c->tnc_mutex);
+ return err;
+}
+
+/**
+ * write_index - write index nodes.
+ * @c: UBIFS file-system description object
+ *
+ * This function writes the index nodes whose positions were laid out in the
+ * layout_in_empty_space function.
+ */
+static int write_index(struct ubifs_info *c)
+{
+ struct ubifs_idx_node *idx;
+ struct ubifs_znode *znode, *cnext;
+ int i, lnum, offs, len, next_len, buf_len, buf_offs, used;
+ int avail, wlen, err, lnum_pos = 0;
+
+ cnext = c->enext;
+ if (!cnext)
+ return 0;
+
+ /*
+ * Always write index nodes to the index head so that index nodes and
+ * other types of nodes are never mixed in the same erase block.
+ */
+ lnum = c->ihead_lnum;
+ buf_offs = c->ihead_offs;
+
+ /* Allocate commit buffer */
+ buf_len = ALIGN(c->max_idx_node_sz, c->min_io_size);
+ used = 0;
+ avail = buf_len;
+
+ /* Ensure there is enough room for first write */
+ next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
+ if (buf_offs + next_len > c->leb_size) {
+ err = ubifs_update_one_lp(c, lnum, LPROPS_NC, 0, 0,
+ LPROPS_TAKEN);
+ if (err)
+ return err;
+ lnum = -1;
+ }
+
+ while (1) {
+ cond_resched();
+
+ znode = cnext;
+ idx = c->cbuf + used;
+
+ /* Make index node */
+ idx->ch.node_type = UBIFS_IDX_NODE;
+ idx->child_cnt = cpu_to_le16(znode->child_cnt);
+ idx->level = cpu_to_le16(znode->level);
+ for (i = 0; i < znode->child_cnt; i++) {
+ struct ubifs_branch *br = ubifs_idx_branch(c, idx, i);
+ struct ubifs_zbranch *zbr = &znode->zbranch[i];
+
+ key_write_idx(c, &zbr->key, &br->key);
+ br->lnum = cpu_to_le32(zbr->lnum);
+ br->offs = cpu_to_le32(zbr->offs);
+ br->len = cpu_to_le32(zbr->len);
+ if (!zbr->lnum || !zbr->len) {
+ ubifs_err("bad ref in znode");
+ dbg_dump_znode(c, znode);
+ if (zbr->znode)
+ dbg_dump_znode(c, zbr->znode);
+ }
+ }
+ len = ubifs_idx_node_sz(c, znode->child_cnt);
+ ubifs_prepare_node(c, idx, len, 0);
+
+ /* Determine the index node position */
+ if (lnum == -1) {
+ lnum = c->ilebs[lnum_pos++];
+ buf_offs = 0;
+ used = 0;
+ avail = buf_len;
+ }
+ offs = buf_offs + used;
+
+#ifdef CONFIG_UBIFS_FS_DEBUG
+ if (lnum != znode->lnum || offs != znode->offs ||
+ len != znode->len) {
+ ubifs_err("inconsistent znode posn");
+ return -EINVAL;
+ }
+#endif
+
+ /* Grab some stuff from znode while we still can */
+ cnext = znode->cnext;
+
+ ubifs_assert(ubifs_zn_dirty(znode));
+ ubifs_assert(test_bit(COW_ZNODE, &znode->flags));
+
+ /*
+ * It is important that other threads should see %DIRTY_ZNODE
+ * flag cleared before %COW_ZNODE. Specifically, it matters in
+ * the 'dirty_cow_znode()' function. This is the reason for the
+ * first barrier. Also, we want the bit changes to be seen to
+ * other threads ASAP, to avoid unnecesarry copying, which is
+ * the reason for the second barrier.
+ */
+ clear_bit(DIRTY_ZNODE, &znode->flags);
+ smp_mb__before_clear_bit();
+ clear_bit(COW_ZNODE, &znode->flags);
+ smp_mb__after_clear_bit();
+
+ /* Do not access znode from this point on */
+
+ /* Update buffer positions */
+ wlen = used + len;
+ used += ALIGN(len, 8);
+ avail -= ALIGN(len, 8);
+
+ /*
+ * Calculate the next index node length to see if there is
+ * enough room for it
+ */
+ if (cnext == c->cnext)
+ next_len = 0;
+ else
+ next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
+
+ if (c->min_io_size == 1) {
+ /*
+ * Write the prepared index node immediately if there is
+ * no minimum IO size
+ */
+ err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs,
+ wlen, UBI_SHORTTERM);
+ if (err)
+ return err;
+ buf_offs += ALIGN(wlen, 8);
+ if (next_len) {
+ used = 0;
+ avail = buf_len;
+ if (buf_offs + next_len > c->leb_size) {
+ err = ubifs_update_one_lp(c, lnum,
+ LPROPS_NC, 0, 0, LPROPS_TAKEN);
+ if (err)
+ return err;
+ lnum = -1;
+ }
+ continue;
+ }
+ } else {
+ int blen, nxt_offs = buf_offs + used + next_len;
+
+ if (next_len && nxt_offs <= c->leb_size) {
+ if (avail > 0)
+ continue;
+ else
+ blen = buf_len;
+ } else {
+ wlen = ALIGN(wlen, 8);
+ blen = ALIGN(wlen, c->min_io_size);
+ ubifs_pad(c, c->cbuf + wlen, blen - wlen);
+ }
+ /*
+ * The buffer is full or there are no more znodes
+ * to do
+ */
+ err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs,
+ blen, UBI_SHORTTERM);
+ if (err)
+ return err;
+ buf_offs += blen;
+ if (next_len) {
+ if (nxt_offs > c->leb_size) {
+ err = ubifs_update_one_lp(c, lnum,
+ LPROPS_NC, 0, 0, LPROPS_TAKEN);
+ if (err)
+ return err;
+ lnum = -1;
+ }
+ used -= blen;
+ if (used < 0)
+ used = 0;
+ avail = buf_len - used;
+ memmove(c->cbuf, c->cbuf + blen, used);
+ continue;
+ }
+ }
+ break;
+ }
+
+#ifdef CONFIG_UBIFS_FS_DEBUG
+ if (lnum != c->new_ihead_lnum || buf_offs != c->new_ihead_offs) {
+ ubifs_err("inconsistent ihead");
+ return -EINVAL;
+ }
+#endif
+
+ c->ihead_lnum = lnum;
+ c->ihead_offs = buf_offs;
+
+ return 0;
+}
+
+/**
+ * free_obsolete_znodes - free obsolete znodes.
+ * @c: UBIFS file-system description object
+ *
+ * At the end of commit end, obsolete znodes are freed.
+ */
+static void free_obsolete_znodes(struct ubifs_info *c)
+{
+ struct ubifs_znode *znode, *cnext;
+
+ cnext = c->cnext;
+ do {
+ znode = cnext;
+ cnext = znode->cnext;
+ if (test_bit(OBSOLETE_ZNODE, &znode->flags))
+ kfree(znode);
+ else {
+ znode->cnext = NULL;
+ atomic_long_inc(&c->clean_zn_cnt);
+ atomic_long_inc(&ubifs_clean_zn_cnt);
+ }
+ } while (cnext != c->cnext);
+}
+
+/**
+ * return_gap_lebs - return LEBs used by the in-gap commit method.
+ * @c: UBIFS file-system description object
+ *
+ * This function clears the "taken" flag for the LEBs which were used by the
+ * "commit in-the-gaps" method.
+ */
+static int return_gap_lebs(struct ubifs_info *c)
+{
+ int *p, err;
+
+ if (!c->gap_lebs)
+ return 0;
+
+ dbg_cmt("");
+ for (p = c->gap_lebs; *p != -1; p++) {
+ err = ubifs_change_one_lp(c, *p, LPROPS_NC, LPROPS_NC, 0,
+ LPROPS_TAKEN, 0);
+ if (err)
+ return err;
+ }
+
+ kfree(c->gap_lebs);
+ c->gap_lebs = NULL;
+ return 0;
+}
+
+/**
+ * ubifs_tnc_end_commit - update the TNC for commit end.
+ * @c: UBIFS file-system description object
+ *
+ * Write the dirty znodes.
+ */
+int ubifs_tnc_end_commit(struct ubifs_info *c)
+{
+ int err;
+
+ if (!c->cnext)
+ return 0;
+
+ err = return_gap_lebs(c);
+ if (err)
+ return err;
+
+ err = write_index(c);
+ if (err)
+ return err;
+
+ mutex_lock(&c->tnc_mutex);
+
+ dbg_cmt("TNC height is %d", c->zroot.znode->level + 1);
+
+ free_obsolete_znodes(c);
+
+ c->cnext = NULL;
+ kfree(c->ilebs);
+ c->ilebs = NULL;
+
+ mutex_unlock(&c->tnc_mutex);
+
+ return 0;
+}
diff --git a/fs/ubifs/tnc_misc.c b/fs/ubifs/tnc_misc.c
new file mode 100644
index 0000000..955219f
--- /dev/null
+++ b/fs/ubifs/tnc_misc.c
@@ -0,0 +1,435 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ * Artem Bityutskiy (Битюцкий Ðртём)
+ */
+
+/*
+ * This file contains miscelanious TNC-related functions shared betweend
+ * different files. This file does not form any logically separate TNC
+ * sub-system. The file was created because there is a lot of TNC code and
+ * putting it all in one file would make that file too big and unreadable.
+ */
+
+#include "ubifs.h"
+
+/**
+ * ubifs_tnc_levelorder_next - next TNC tree element in levelorder traversal.
+ * @zr: root of the subtree to traverse
+ * @znode: previous znode
+ *
+ * This function implements levelorder TNC traversal. The LNC is ignored.
+ * Returns the next element or %NULL if @znode is already the last one.
+ */
+struct ubifs_znode *ubifs_tnc_levelorder_next(struct ubifs_znode *zr,
+ struct ubifs_znode *znode)
+{
+ int level, iip, level_search = 0;
+ struct ubifs_znode *zn;
+
+ ubifs_assert(zr);
+
+ if (unlikely(!znode))
+ return zr;
+
+ if (unlikely(znode == zr)) {
+ if (znode->level == 0)
+ return NULL;
+ return ubifs_tnc_find_child(zr, 0);
+ }
+
+ level = znode->level;
+
+ iip = znode->iip;
+ while (1) {
+ ubifs_assert(znode->level <= zr->level);
+
+ /*
+ * First walk up until there is a znode with next branch to
+ * look at.
+ */
+ while (znode->parent != zr && iip >= znode->parent->child_cnt) {
+ znode = znode->parent;
+ iip = znode->iip;
+ }
+
+ if (unlikely(znode->parent == zr &&
+ iip >= znode->parent->child_cnt)) {
+ /* This level is done, switch to the lower one */
+ level -= 1;
+ if (level_search || level < 0)
+ /*
+ * We were already looking for znode at lower
+ * level ('level_search'). As we are here
+ * again, it just does not exist. Or all levels
+ * were finished ('level < 0').
+ */
+ return NULL;
+
+ level_search = 1;
+ iip = -1;
+ znode = ubifs_tnc_find_child(zr, 0);
+ ubifs_assert(znode);
+ }
+
+ /* Switch to the next index */
+ zn = ubifs_tnc_find_child(znode->parent, iip + 1);
+ if (!zn) {
+ /* No more children to look at, we have walk up */
+ iip = znode->parent->child_cnt;
+ continue;
+ }
+
+ /* Walk back down to the level we came from ('level') */
+ while (zn->level != level) {
+ znode = zn;
+ zn = ubifs_tnc_find_child(zn, 0);
+ if (!zn) {
+ /*
+ * This path is not too deep so it does not
+ * reach 'level'. Try next path.
+ */
+ iip = znode->iip;
+ break;
+ }
+ }
+
+ if (zn) {
+ ubifs_assert(zn->level >= 0);
+ return zn;
+ }
+ }
+}
+
+/**
+ * ubifs_search_zbranch - search znode branch.
+ * @c: UBIFS file-system description object
+ * @znode: znode to search in
+ * @key: key to search for
+ * @n: znode branch slot number is returned here
+ *
+ * This is a helper function which search branch with key @key in @znode using
+ * binary search. The result of the search may be:
+ * o exact match, then %1 is returned, and the slot number of the branch is
+ * stored in @n;
+ * o no exact match, then %0 is returned and the slot number of the left
+ * closest branch is returned in @n; the slot if all keys in this znode are
+ * greater than @key, then %-1 is returned in @n.
+ */
+int ubifs_search_zbranch(const struct ubifs_info *c,
+ const struct ubifs_znode *znode,
+ const union ubifs_key *key, int *n)
+{
+ int beg = 0, end = znode->child_cnt, uninitialized_var(mid);
+ int uninitialized_var(cmp);
+ const struct ubifs_zbranch *zbr = &znode->zbranch[0];
+
+ ubifs_assert(end > beg);
+
+ while (end > beg) {
+ mid = (beg + end) >> 1;
+ cmp = keys_cmp(c, key, &zbr[mid].key);
+ if (cmp > 0)
+ beg = mid + 1;
+ else if (cmp < 0)
+ end = mid;
+ else {
+ *n = mid;
+ return 1;
+ }
+ }
+
+ *n = end - 1;
+
+ /* The insert point is after *n */
+ ubifs_assert(*n >= -1 && *n < znode->child_cnt);
+ if (*n == -1)
+ ubifs_assert(keys_cmp(c, key, &zbr[0].key) < 0);
+ else
+ ubifs_assert(keys_cmp(c, key, &zbr[*n].key) > 0);
+ if (*n + 1 < znode->child_cnt)
+ ubifs_assert(keys_cmp(c, key, &zbr[*n + 1].key) < 0);
+
+ return 0;
+}
+
+/**
+ * ubifs_tnc_postorder_first - find first znode to do postorder tree traversal.
+ * @znode: znode to start at (root of the sub-tree to traverse)
+ *
+ * Find the lowest leftmost znode in a subtree of the TNC tree. The LNC is
+ * ignored.
+ */
+struct ubifs_znode *ubifs_tnc_postorder_first(struct ubifs_znode *znode)
+{
+ if (unlikely(!znode))
+ return NULL;
+
+ while (znode->level > 0) {
+ struct ubifs_znode *child;
+
+ child = ubifs_tnc_find_child(znode, 0);
+ if (!child)
+ return znode;
+ znode = child;
+ }
+
+ return znode;
+}
+
+/**
+ * ubifs_tnc_postorder_next - next TNC tree element in postorder traversal.
+ * @znode: previous znode
+ *
+ * This function implements postorder TNC traversal. The LNC is ignored.
+ * Returns the next element or %NULL if @znode is already the last one.
+ */
+struct ubifs_znode *ubifs_tnc_postorder_next(struct ubifs_znode *znode)
+{
+ struct ubifs_znode *zn;
+
+ ubifs_assert(znode);
+ if (unlikely(!znode->parent))
+ return NULL;
+
+ /* Switch to the next index in the parent */
+ zn = ubifs_tnc_find_child(znode->parent, znode->iip + 1);
+ if (!zn)
+ /* This is in fact the last child, return parent */
+ return znode->parent;
+
+ /* Go to the first znode in this new subtree */
+ return ubifs_tnc_postorder_first(zn);
+}
+
+/**
+ * read_znode - read an indexing node from flash and fill znode.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB of the indexing node to read
+ * @offs: node offset
+ * @len: node length
+ * @znode: znode to read to
+ *
+ * This function reads an indexing node from the flash media and fills znode
+ * with the read data. Returns zero in case of success and a negative error
+ * code in case of failure. The read indexing node is validated and if anything
+ * is wrong with it, this function prints complaint messages and returns
+ * %-EINVAL.
+ */
+static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
+ struct ubifs_znode *znode)
+{
+ int i, err, type, cmp;
+ struct ubifs_idx_node *idx;
+
+ idx = kmalloc(c->max_idx_node_sz, GFP_NOFS);
+ if (!idx)
+ return -ENOMEM;
+
+ err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs);
+ if (err < 0) {
+ kfree(idx);
+ return err;
+ }
+
+ znode->child_cnt = le16_to_cpu(idx->child_cnt);
+ znode->level = le16_to_cpu(idx->level);
+
+ dbg_tnc("LEB %d:%d, level %d, %d branch",
+ lnum, offs, znode->level, znode->child_cnt);
+
+ if (znode->child_cnt > c->fanout || znode->level > UBIFS_MAX_LEVELS) {
+ dbg_err("current fanout %d, branch count %d",
+ c->fanout, znode->child_cnt);
+ dbg_err("max levels %d, znode level %d",
+ UBIFS_MAX_LEVELS, znode->level);
+ err = 1;
+ goto out_dump;
+ }
+
+ for (i = 0; i < znode->child_cnt; i++) {
+ const struct ubifs_branch *br = ubifs_idx_branch(c, idx, i);
+ struct ubifs_zbranch *zbr = &znode->zbranch[i];
+
+ key_read(c, &br->key, &zbr->key);
+ zbr->lnum = le32_to_cpu(br->lnum);
+ zbr->offs = le32_to_cpu(br->offs);
+ zbr->len = le32_to_cpu(br->len);
+ zbr->znode = NULL;
+
+ /* Validate branch */
+
+ if (zbr->lnum < c->main_first ||
+ zbr->lnum >= c->leb_cnt || zbr->offs < 0 ||
+ zbr->offs + zbr->len > c->leb_size || zbr->offs & 7) {
+ dbg_err("bad branch %d", i);
+ err = 2;
+ goto out_dump;
+ }
+
+ switch (key_type(c, &zbr->key)) {
+ case UBIFS_INO_KEY:
+ case UBIFS_DATA_KEY:
+ case UBIFS_DENT_KEY:
+ case UBIFS_XENT_KEY:
+ break;
+ default:
+ dbg_msg("bad key type at slot %d: %s", i,
+ DBGKEY(&zbr->key));
+ err = 3;
+ goto out_dump;
+ }
+
+ if (znode->level)
+ continue;
+
+ type = key_type(c, &zbr->key);
+ if (c->ranges[type].max_len == 0) {
+ if (zbr->len != c->ranges[type].len) {
+ dbg_err("bad target node (type %d) length (%d)",
+ type, zbr->len);
+ dbg_err("have to be %d", c->ranges[type].len);
+ err = 4;
+ goto out_dump;
+ }
+ } else if (zbr->len < c->ranges[type].min_len ||
+ zbr->len > c->ranges[type].max_len) {
+ dbg_err("bad target node (type %d) length (%d)",
+ type, zbr->len);
+ dbg_err("have to be in range of %d-%d",
+ c->ranges[type].min_len,
+ c->ranges[type].max_len);
+ err = 5;
+ goto out_dump;
+ }
+ }
+
+ /*
+ * Ensure that the next key is greater or equivalent to the
+ * previous one.
+ */
+ for (i = 0; i < znode->child_cnt - 1; i++) {
+ const union ubifs_key *key1, *key2;
+
+ key1 = &znode->zbranch[i].key;
+ key2 = &znode->zbranch[i + 1].key;
+
+ cmp = keys_cmp(c, key1, key2);
+ if (cmp > 0) {
+ dbg_err("bad key order (keys %d and %d)", i, i + 1);
+ err = 6;
+ goto out_dump;
+ } else if (cmp == 0 && !is_hash_key(c, key1)) {
+ /* These can only be keys with colliding hash */
+ dbg_err("keys %d and %d are not hashed but equivalent",
+ i, i + 1);
+ err = 7;
+ goto out_dump;
+ }
+ }
+
+ kfree(idx);
+ return 0;
+
+out_dump:
+ ubifs_err("bad indexing node at LEB %d:%d, error %d", lnum, offs, err);
+ dbg_dump_node(c, idx);
+ kfree(idx);
+ return -EINVAL;
+}
+
+/**
+ * ubifs_load_znode - load znode to TNC cache.
+ * @c: UBIFS file-system description object
+ * @zbr: znode branch
+ * @parent: znode's parent
+ * @iip: index in parent
+ *
+ * This function loads znode pointed to by @zbr into the TNC cache and
+ * returns pointer to it in case of success and a negative error code in case
+ * of failure.
+ */
+struct ubifs_znode *ubifs_load_znode(struct ubifs_info *c,
+ struct ubifs_zbranch *zbr,
+ struct ubifs_znode *parent, int iip)
+{
+ int err;
+ struct ubifs_znode *znode;
+
+ ubifs_assert(!zbr->znode);
+ /*
+ * A slab cache is not presently used for znodes because the znode size
+ * depends on the fanout which is stored in the superblock.
+ */
+ znode = kzalloc(c->max_znode_sz, GFP_NOFS);
+ if (!znode)
+ return ERR_PTR(-ENOMEM);
+
+ err = read_znode(c, zbr->lnum, zbr->offs, zbr->len, znode);
+ if (err)
+ goto out;
+
+ zbr->znode = znode;
+ znode->parent = parent;
+ znode->time = get_seconds();
+ znode->iip = iip;
+
+ return znode;
+
+out:
+ kfree(znode);
+ return ERR_PTR(err);
+}
+
+/**
+ * ubifs_tnc_read_node - read a leaf node from the flash media.
+ * @c: UBIFS file-system description object
+ * @zbr: key and position of the node
+ * @node: node is returned here
+ *
+ * This function reads a node defined by @zbr from the flash media. Returns
+ * zero in case of success or a negative negative error code in case of
+ * failure.
+ */
+int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+ void *node)
+{
+ union ubifs_key key1, *key = &zbr->key;
+ int err, type = key_type(c, key);
+
+ err = ubifs_read_node(c, node, type, zbr->len, zbr->lnum, zbr->offs);
+
+ if (err) {
+ dbg_tnc("key %s", DBGKEY(key));
+ return err;
+ }
+
+ /* Make sure the key of the read node is correct */
+ key_read(c, node + UBIFS_KEY_OFFSET, &key1);
+ if (!keys_eq(c, key, &key1)) {
+ ubifs_err("bad key in node at LEB %d:%d",
+ zbr->lnum, zbr->offs);
+ dbg_tnc("looked for key %s found node's key %s",
+ DBGKEY(key), DBGKEY1(&key1));
+ dbg_dump_node(c, node);
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
new file mode 100644
index 0000000..b25fc36
--- /dev/null
+++ b/fs/ubifs/ubifs-media.h
@@ -0,0 +1,751 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Ðртём)
+ * Adrian Hunter
+ */
+
+/*
+ * This file describes UBIFS on-flash format and contains definitions of all the
+ * relevant data structures and constants.
+ *
+ * All UBIFS on-flash objects are stored in the form of nodes. All nodes start
+ * with the UBIFS node magic number and have the same common header. Nodes
+ * always sit at 8-byte aligned positions on the media and node header sizes are
+ * also 8-byte aligned (except for the indexing node and the padding node).
+ */
+
+#ifndef __UBIFS_MEDIA_H__
+#define __UBIFS_MEDIA_H__
+
+/* UBIFS node magic number (must not have the padding byte first or last) */
+#define UBIFS_NODE_MAGIC 0x06101831
+
+/* UBIFS on-flash format version */
+#define UBIFS_FORMAT_VERSION 4
+
+/* Minimum logical eraseblock size in bytes */
+#define UBIFS_MIN_LEB_SZ (15*1024)
+
+/* Initial CRC32 value used when calculating CRC checksums */
+#define UBIFS_CRC32_INIT 0xFFFFFFFFU
+
+/*
+ * UBIFS does not try to compress data if its length is less than the below
+ * constant.
+ */
+#define UBIFS_MIN_COMPR_LEN 128
+
+/*
+ * If compressed data length is less than %UBIFS_MIN_COMPRESS_DIFF bytes
+ * shorter than uncompressed data length, UBIFS preferes to leave this data
+ * node uncompress, because it'll be read faster.
+ */
+#define UBIFS_MIN_COMPRESS_DIFF 64
+
+/* Root inode number */
+#define UBIFS_ROOT_INO 1
+
+/* Lowest inode number used for regular inodes (not UBIFS-only internal ones) */
+#define UBIFS_FIRST_INO 64
+
+/*
+ * Maximum file name and extended attribute length (must be a multiple of 8,
+ * minus 1).
+ */
+#define UBIFS_MAX_NLEN 255
+
+/* Maximum number of data journal heads */
+#define UBIFS_MAX_JHEADS 1
+
+/*
+ * Size of UBIFS data block. Note, UBIFS is not a block oriented file-system,
+ * which means that it does not treat the underlying media as consisting of
+ * blocks like in case of hard drives. Do not be confused. UBIFS block is just
+ * the maximum amount of data which one data node can have or which can be
+ * attached to an inode node.
+ */
+#define UBIFS_BLOCK_SIZE 4096
+#define UBIFS_BLOCK_SHIFT 12
+
+/* UBIFS padding byte pattern (must not be first or last byte of node magic) */
+#define UBIFS_PADDING_BYTE 0xCE
+
+/* Maximum possible key length */
+#define UBIFS_MAX_KEY_LEN 16
+
+/* Key length ("simple" format) */
+#define UBIFS_SK_LEN 8
+
+/* Minimum index tree fanout */
+#define UBIFS_MIN_FANOUT 3
+
+/* Maximum number of levels in UBIFS indexing B-tree */
+#define UBIFS_MAX_LEVELS 512
+
+/* Maximum amount of data attached to an inode in bytes */
+#define UBIFS_MAX_INO_DATA UBIFS_BLOCK_SIZE
+
+/* LEB Properties Tree fanout (must be power of 2) and fanout shift */
+#define UBIFS_LPT_FANOUT 4
+#define UBIFS_LPT_FANOUT_SHIFT 2
+
+/* LEB Properties Tree bit field sizes */
+#define UBIFS_LPT_CRC_BITS 16
+#define UBIFS_LPT_CRC_BYTES 2
+#define UBIFS_LPT_TYPE_BITS 4
+
+/* The key is always at the same position in all keyed nodes */
+#define UBIFS_KEY_OFFSET offsetof(struct ubifs_ino_node, key)
+
+/*
+ * LEB Properties Tree node types.
+ *
+ * UBIFS_LPT_PNODE: LPT leaf node (contains LEB properties)
+ * UBIFS_LPT_NNODE: LPT internal node
+ * UBIFS_LPT_LTAB: LPT's own lprops table
+ * UBIFS_LPT_LSAVE: LPT's save table (big model only)
+ * UBIFS_LPT_NODE_CNT: count of LPT node types
+ * UBIFS_LPT_NOT_A_NODE: all ones (15 for 4 bits) is never a valid node type
+ */
+enum {
+ UBIFS_LPT_PNODE,
+ UBIFS_LPT_NNODE,
+ UBIFS_LPT_LTAB,
+ UBIFS_LPT_LSAVE,
+ UBIFS_LPT_NODE_CNT,
+ UBIFS_LPT_NOT_A_NODE = (1 << UBIFS_LPT_TYPE_BITS) - 1,
+};
+
+/*
+ * UBIFS inode types.
+ *
+ * UBIFS_ITYPE_REG: regular file
+ * UBIFS_ITYPE_DIR: directory
+ * UBIFS_ITYPE_LNK: soft link
+ * UBIFS_ITYPE_BLK: block device node
+ * UBIFS_ITYPE_CHR: character device node
+ * UBIFS_ITYPE_FIFO: fifo
+ * UBIFS_ITYPE_SOCK: socket
+ * UBIFS_ITYPES_CNT: count of supported file types
+ */
+enum {
+ UBIFS_ITYPE_REG,
+ UBIFS_ITYPE_DIR,
+ UBIFS_ITYPE_LNK,
+ UBIFS_ITYPE_BLK,
+ UBIFS_ITYPE_CHR,
+ UBIFS_ITYPE_FIFO,
+ UBIFS_ITYPE_SOCK,
+ UBIFS_ITYPES_CNT,
+};
+
+/*
+ * Supported key hash functions.
+ *
+ * UBIFS_KEY_HASH_R5: R5 hash
+ * UBIFS_KEY_HASH_TEST: test hash which just returns first 4 bytes of the name
+ */
+enum {
+ UBIFS_KEY_HASH_R5,
+ UBIFS_KEY_HASH_TEST,
+};
+
+/*
+ * Supported key formats.
+ *
+ * UBIFS_SIMPLE_KEY_FMT: simple key format
+ */
+enum {
+ UBIFS_SIMPLE_KEY_FMT,
+};
+
+/*
+ * The simple key format uses 29 bits for storing UBIFS block number and hash
+ * value.
+ */
+#define UBIFS_S_KEY_BLOCK_BITS 29
+#define UBIFS_S_KEY_BLOCK_MASK 0x1FFFFFFF
+#define UBIFS_S_KEY_HASH_BITS UBIFS_S_KEY_BLOCK_BITS
+#define UBIFS_S_KEY_HASH_MASK UBIFS_S_KEY_BLOCK_MASK
+
+/*
+ * Key types.
+ *
+ * UBIFS_INO_KEY: inode node key
+ * UBIFS_DATA_KEY: data node key
+ * UBIFS_DENT_KEY: directory entry node key
+ * UBIFS_XENT_KEY: extended attribute entry key
+ * UBIFS_KEY_TYPES_CNT: number of supported key types
+ */
+enum {
+ UBIFS_INO_KEY,
+ UBIFS_DATA_KEY,
+ UBIFS_DENT_KEY,
+ UBIFS_XENT_KEY,
+ UBIFS_KEY_TYPES_CNT,
+};
+
+/* Count of LEBs reserved for the superblock area */
+#define UBIFS_SB_LEBS 1
+/* Count of LEBs reserved for the master area */
+#define UBIFS_MST_LEBS 2
+
+/* First LEB of the superblock area */
+#define UBIFS_SB_LNUM 0
+/* First LEB of the master area */
+#define UBIFS_MST_LNUM (UBIFS_SB_LNUM + UBIFS_SB_LEBS)
+/* First LEB of the log area */
+#define UBIFS_LOG_LNUM (UBIFS_MST_LNUM + UBIFS_MST_LEBS)
+
+/*
+ * The below constants define the absolute minimum values for various UBIFS
+ * media areas. Many of them actually depend of flash geometry and the FS
+ * configuration (number of journal heads, orphan LEBs, etc). This means that
+ * the smallest volume size which can be used for UBIFS cannot be pre-defined
+ * by these constants. The file-system that meets the below limitation will not
+ * necessarily mount. UBIFS does run-time calculations and validates the FS
+ * size.
+ */
+
+/* Minimum number of logical eraseblocks in the log */
+#define UBIFS_MIN_LOG_LEBS 2
+/* Minimum number of bud logical eraseblocks (one for each head) */
+#define UBIFS_MIN_BUD_LEBS 3
+/* Minimum number of journal logical eraseblocks */
+#define UBIFS_MIN_JNL_LEBS (UBIFS_MIN_LOG_LEBS + UBIFS_MIN_BUD_LEBS)
+/* Minimum number of LPT area logical eraseblocks */
+#define UBIFS_MIN_LPT_LEBS 2
+/* Minimum number of orphan area logical eraseblocks */
+#define UBIFS_MIN_ORPH_LEBS 1
+/*
+ * Minimum number of main area logical eraseblocks (buds, 3 for the index, 1
+ * for GC, 1 for deletions, and at least 1 for committed data).
+ */
+#define UBIFS_MIN_MAIN_LEBS (UBIFS_MIN_BUD_LEBS + 6)
+
+/* Minimum number of logical eraseblocks */
+#define UBIFS_MIN_LEB_CNT (UBIFS_SB_LEBS + UBIFS_MST_LEBS + \
+ UBIFS_MIN_LOG_LEBS + UBIFS_MIN_LPT_LEBS + \
+ UBIFS_MIN_ORPH_LEBS + UBIFS_MIN_MAIN_LEBS)
+
+/* Node sizes (N.B. these are guaranteed to be multiples of 8) */
+#define UBIFS_CH_SZ sizeof(struct ubifs_ch)
+#define UBIFS_INO_NODE_SZ sizeof(struct ubifs_ino_node)
+#define UBIFS_DATA_NODE_SZ sizeof(struct ubifs_data_node)
+#define UBIFS_DENT_NODE_SZ sizeof(struct ubifs_dent_node)
+#define UBIFS_TRUN_NODE_SZ sizeof(struct ubifs_trun_node)
+#define UBIFS_PAD_NODE_SZ sizeof(struct ubifs_pad_node)
+#define UBIFS_SB_NODE_SZ sizeof(struct ubifs_sb_node)
+#define UBIFS_MST_NODE_SZ sizeof(struct ubifs_mst_node)
+#define UBIFS_REF_NODE_SZ sizeof(struct ubifs_ref_node)
+#define UBIFS_IDX_NODE_SZ sizeof(struct ubifs_idx_node)
+#define UBIFS_CS_NODE_SZ sizeof(struct ubifs_cs_node)
+#define UBIFS_ORPH_NODE_SZ sizeof(struct ubifs_orph_node)
+/* Extended attribute entry nodes are identical to directory entry nodes */
+#define UBIFS_XENT_NODE_SZ UBIFS_DENT_NODE_SZ
+/* Only this does not have to be multiple of 8 bytes */
+#define UBIFS_BRANCH_SZ sizeof(struct ubifs_branch)
+
+/* Maximum node sizes (N.B. these are guaranteed to be multiples of 8) */
+#define UBIFS_MAX_DATA_NODE_SZ (UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE)
+#define UBIFS_MAX_INO_NODE_SZ (UBIFS_INO_NODE_SZ + UBIFS_MAX_INO_DATA)
+#define UBIFS_MAX_DENT_NODE_SZ (UBIFS_DENT_NODE_SZ + UBIFS_MAX_NLEN + 1)
+#define UBIFS_MAX_XENT_NODE_SZ UBIFS_MAX_DENT_NODE_SZ
+
+/* The largest UBIFS node */
+#define UBIFS_MAX_NODE_SZ UBIFS_MAX_INO_NODE_SZ
+
+/*
+ * On-flash inode flags.
+ *
+ * UBIFS_COMPR_FL: use compression for this inode
+ * UBIFS_SYNC_FL: I/O on this inode has to be synchronous
+ * UBIFS_IMMUTABLE_FL: inode is immutable
+ * UBIFS_APPEND_FL: writes to the inode may only append data
+ * UBIFS_DIRSYNC_FL: I/O on this directory inode has to be synchronous
+ * UBIFS_XATTR_FL: this inode is the inode for an extended attribute value
+ *
+ * Note, these are on-flash flags which correspond to ioctl flags
+ * (@FS_COMPR_FL, etc). They have the same values now, but generally, do not
+ * have to be the same.
+ */
+enum {
+ UBIFS_COMPR_FL = 0x01,
+ UBIFS_SYNC_FL = 0x02,
+ UBIFS_IMMUTABLE_FL = 0x04,
+ UBIFS_APPEND_FL = 0x08,
+ UBIFS_DIRSYNC_FL = 0x10,
+ UBIFS_XATTR_FL = 0x20,
+};
+
+/* Inode flag bits used by UBIFS */
+#define UBIFS_FL_MASK 0x0000001F
+
+/*
+ * UBIFS compression algorithms.
+ *
+ * UBIFS_COMPR_NONE: no compression
+ * UBIFS_COMPR_LZO: LZO compression
+ * UBIFS_COMPR_ZLIB: ZLIB compression
+ * UBIFS_COMPR_TYPES_CNT: count of supported compression types
+ */
+enum {
+ UBIFS_COMPR_NONE,
+ UBIFS_COMPR_LZO,
+ UBIFS_COMPR_ZLIB,
+ UBIFS_COMPR_TYPES_CNT,
+};
+
+/*
+ * UBIFS node types.
+ *
+ * UBIFS_INO_NODE: inode node
+ * UBIFS_DATA_NODE: data node
+ * UBIFS_DENT_NODE: directory entry node
+ * UBIFS_XENT_NODE: extended attribute node
+ * UBIFS_TRUN_NODE: truncation node
+ * UBIFS_PAD_NODE: padding node
+ * UBIFS_SB_NODE: superblock node
+ * UBIFS_MST_NODE: master node
+ * UBIFS_REF_NODE: LEB reference node
+ * UBIFS_IDX_NODE: index node
+ * UBIFS_CS_NODE: commit start node
+ * UBIFS_ORPH_NODE: orphan node
+ * UBIFS_NODE_TYPES_CNT: count of supported node types
+ *
+ * Note, we index arrays by these numbers, so keep them low and contiguous.
+ * Node type constants for inodes, direntries and so on have to be the same as
+ * corresponding key type constants.
+ */
+enum {
+ UBIFS_INO_NODE,
+ UBIFS_DATA_NODE,
+ UBIFS_DENT_NODE,
+ UBIFS_XENT_NODE,
+ UBIFS_TRUN_NODE,
+ UBIFS_PAD_NODE,
+ UBIFS_SB_NODE,
+ UBIFS_MST_NODE,
+ UBIFS_REF_NODE,
+ UBIFS_IDX_NODE,
+ UBIFS_CS_NODE,
+ UBIFS_ORPH_NODE,
+ UBIFS_NODE_TYPES_CNT,
+};
+
+/*
+ * Master node flags.
+ *
+ * UBIFS_MST_DIRTY: rebooted uncleanly - master node is dirty
+ * UBIFS_MST_NO_ORPHS: no orphan inodes present
+ * UBIFS_MST_RCVRY: written by recovery
+ */
+enum {
+ UBIFS_MST_DIRTY = 1,
+ UBIFS_MST_NO_ORPHS = 2,
+ UBIFS_MST_RCVRY = 4,
+};
+
+/*
+ * Node group type (used by recovery to recover whole group or none).
+ *
+ * UBIFS_NO_NODE_GROUP: this node is not part of a group
+ * UBIFS_IN_NODE_GROUP: this node is a part of a group
+ * UBIFS_LAST_OF_NODE_GROUP: this node is the last in a group
+ */
+enum {
+ UBIFS_NO_NODE_GROUP = 0,
+ UBIFS_IN_NODE_GROUP,
+ UBIFS_LAST_OF_NODE_GROUP,
+};
+
+/*
+ * Superblock flags.
+ *
+ * UBIFS_FLG_BIGLPT: if "big" LPT model is used if set
+ */
+enum {
+ UBIFS_FLG_BIGLPT = 0x02,
+};
+
+/**
+ * struct ubifs_ch - common header node.
+ * @magic: UBIFS node magic number (%UBIFS_NODE_MAGIC)
+ * @crc: CRC-32 checksum of the node header
+ * @sqnum: sequence number
+ * @len: full node length
+ * @node_type: node type
+ * @group_type: node group type
+ * @padding: reserved for future, zeroes
+ *
+ * Every UBIFS node starts with this common part. If the node has a key, the
+ * key always goes next.
+ */
+struct ubifs_ch {
+ __le32 magic;
+ __le32 crc;
+ __le64 sqnum;
+ __le32 len;
+ __u8 node_type;
+ __u8 group_type;
+ __u8 padding[2];
+} __attribute__ ((packed));
+
+/**
+ * union ubifs_dev_desc - device node descriptor.
+ * @new: new type device descriptor
+ * @huge: huge type device descriptor
+ *
+ * This data structure describes major/minor numbers of a device node. In an
+ * inode is a device node then its data contains an object of this type. UBIFS
+ * uses standard Linux "new" and "huge" device node encodings.
+ */
+union ubifs_dev_desc {
+ __le32 new;
+ __le64 huge;
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_ino_node - inode node.
+ * @ch: common header
+ * @key: node key
+ * @creat_sqnum: sequence number at time of creation
+ * @size: inode size in bytes (amount of uncompressed data)
+ * @atime_sec: access time seconds
+ * @ctime_sec: creation time seconds
+ * @mtime_sec: modification time seconds
+ * @atime_nsec: access time nanoseconds
+ * @ctime_nsec: creation time nanoseconds
+ * @mtime_nsec: modification time nanoseconds
+ * @nlink: number of hard links
+ * @uid: owner ID
+ * @gid: group ID
+ * @mode: access flags
+ * @flags: per-inode flags (%UBIFS_COMPR_FL, %UBIFS_SYNC_FL, etc)
+ * @data_len: inode data length
+ * @xattr_cnt: count of extended attributes this inode has
+ * @xattr_size: summarized size of all extended attributes in bytes
+ * @padding1: reserved for future, zeroes
+ * @xattr_names: sum of lengths of all extended attribute names belonging to
+ * this inode
+ * @compr_type: compression type used for this inode
+ * @padding2: reserved for future, zeroes
+ * @data: data attached to the inode
+ *
+ * Note, even though inode compression type is defined by @compr_type, some
+ * nodes of this inode may be compressed with different compressor - this
+ * happens if compression type is changed while the inode already has data
+ * nodes. But @compr_type will be use for further writes to the inode.
+ *
+ * Note, do not forget to amend 'zero_ino_node_unused()' function when changing
+ * the padding fields.
+ */
+struct ubifs_ino_node {
+ struct ubifs_ch ch;
+ __u8 key[UBIFS_MAX_KEY_LEN];
+ __le64 creat_sqnum;
+ __le64 size;
+ __le64 atime_sec;
+ __le64 ctime_sec;
+ __le64 mtime_sec;
+ __le32 atime_nsec;
+ __le32 ctime_nsec;
+ __le32 mtime_nsec;
+ __le32 nlink;
+ __le32 uid;
+ __le32 gid;
+ __le32 mode;
+ __le32 flags;
+ __le32 data_len;
+ __le32 xattr_cnt;
+ __le32 xattr_size;
+ __u8 padding1[4]; /* Watch 'zero_ino_node_unused()' if changing! */
+ __le32 xattr_names;
+ __le16 compr_type;
+ __u8 padding2[26]; /* Watch 'zero_ino_node_unused()' if changing! */
+ __u8 data[];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_dent_node - directory entry node.
+ * @ch: common header
+ * @key: node key
+ * @inum: target inode number
+ * @padding1: reserved for future, zeroes
+ * @type: type of the target inode (%UBIFS_ITYPE_REG, %UBIFS_ITYPE_DIR, etc)
+ * @nlen: name length
+ * @padding2: reserved for future, zeroes
+ * @name: zero-terminated name
+ *
+ * Note, do not forget to amend 'zero_dent_node_unused()' function when
+ * changing the padding fields.
+ */
+struct ubifs_dent_node {
+ struct ubifs_ch ch;
+ __u8 key[UBIFS_MAX_KEY_LEN];
+ __le64 inum;
+ __u8 padding1;
+ __u8 type;
+ __le16 nlen;
+ __u8 padding2[4]; /* Watch 'zero_dent_node_unused()' if changing! */
+ __u8 name[];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_data_node - data node.
+ * @ch: common header
+ * @key: node key
+ * @size: uncompressed data size in bytes
+ * @compr_type: compression type (%UBIFS_COMPR_NONE, %UBIFS_COMPR_LZO, etc)
+ * @padding: reserved for future, zeroes
+ * @data: data
+ *
+ * Note, do not forget to amend 'zero_data_node_unused()' function when
+ * changing the padding fields.
+ */
+struct ubifs_data_node {
+ struct ubifs_ch ch;
+ __u8 key[UBIFS_MAX_KEY_LEN];
+ __le32 size;
+ __le16 compr_type;
+ __u8 padding[2]; /* Watch 'zero_data_node_unused()' if changing! */
+ __u8 data[];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_trun_node - truncation node.
+ * @ch: common header
+ * @inum: truncated inode number
+ * @padding: reserved for future, zeroes
+ * @old_size: size before truncation
+ * @new_size: size after truncation
+ *
+ * This node exists only in the journal and never goes to the main area. Note,
+ * do not forget to amend 'zero_trun_node_unused()' function when changing the
+ * padding fields.
+ */
+struct ubifs_trun_node {
+ struct ubifs_ch ch;
+ __le32 inum;
+ __u8 padding[12]; /* Watch 'zero_trun_node_unused()' if changing! */
+ __le64 old_size;
+ __le64 new_size;
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_pad_node - padding node.
+ * @ch: common header
+ * @pad_len: how many bytes after this node are unused (because padded)
+ * @padding: reserved for future, zeroes
+ */
+struct ubifs_pad_node {
+ struct ubifs_ch ch;
+ __le32 pad_len;
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_sb_node - superblock node.
+ * @ch: common header
+ * @padding: reserved for future, zeroes
+ * @key_hash: type of hash function used in keys
+ * @key_fmt: format of the key
+ * @flags: file-system flags (%UBIFS_FLG_BIGLPT, etc)
+ * @min_io_size: minimal input/output unit size
+ * @leb_size: logical eraseblock size in bytes
+ * @leb_cnt: count of LEBs used by file-system
+ * @max_leb_cnt: maximum count of LEBs used by file-system
+ * @max_bud_bytes: maximum amount of data stored in buds
+ * @log_lebs: log size in logical eraseblocks
+ * @lpt_lebs: number of LEBs used for lprops table
+ * @orph_lebs: number of LEBs used for recording orphans
+ * @jhead_cnt: count of journal heads
+ * @fanout: tree fanout (max. number of links per indexing node)
+ * @lsave_cnt: number of LEB numbers in LPT's save table
+ * @fmt_version: UBIFS on-flash format version
+ * @default_compr: default compression algorithm (%UBIFS_COMPR_LZO, etc)
+ * @padding1: reserved for future, zeroes
+ * @rp_uid: reserve pool UID
+ * @rp_gid: reserve pool GID
+ * @rp_size: size of the reserved pool in bytes
+ * @padding2: reserved for future, zeroes
+ * @time_gran: time granularity in nanoseconds
+ * @uuid: UUID generated when the file system image was created
+ */
+struct ubifs_sb_node {
+ struct ubifs_ch ch;
+ __u8 padding[2];
+ __u8 key_hash;
+ __u8 key_fmt;
+ __le32 flags;
+ __le32 min_io_size;
+ __le32 leb_size;
+ __le32 leb_cnt;
+ __le32 max_leb_cnt;
+ __le64 max_bud_bytes;
+ __le32 log_lebs;
+ __le32 lpt_lebs;
+ __le32 orph_lebs;
+ __le32 jhead_cnt;
+ __le32 fanout;
+ __le32 lsave_cnt;
+ __le32 fmt_version;
+ __le16 default_compr;
+ __u8 padding1[2];
+ __le32 rp_uid;
+ __le32 rp_gid;
+ __le64 rp_size;
+ __le32 time_gran;
+ __u8 uuid[16];
+ __u8 padding2[3972];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_mst_node - master node.
+ * @ch: common header
+ * @highest_inum: highest inode number in the committed index
+ * @cmt_no: commit number
+ * @flags: various flags (%UBIFS_MST_DIRTY, etc)
+ * @log_lnum: start of the log
+ * @root_lnum: LEB number of the root indexing node
+ * @root_offs: offset within @root_lnum
+ * @root_len: root indexing node length
+ * @gc_lnum: LEB reserved for garbage collection (%-1 value means the LEB was
+ * not reserved and should be reserved on mount)
+ * @ihead_lnum: LEB number of index head
+ * @ihead_offs: offset of index head
+ * @index_size: size of index on flash
+ * @total_free: total free space in bytes
+ * @total_dirty: total dirty space in bytes
+ * @total_used: total used space in bytes (includes only data LEBs)
+ * @total_dead: total dead space in bytes (includes only data LEBs)
+ * @total_dark: total dark space in bytes (includes only data LEBs)
+ * @lpt_lnum: LEB number of LPT root nnode
+ * @lpt_offs: offset of LPT root nnode
+ * @nhead_lnum: LEB number of LPT head
+ * @nhead_offs: offset of LPT head
+ * @ltab_lnum: LEB number of LPT's own lprops table
+ * @ltab_offs: offset of LPT's own lprops table
+ * @lsave_lnum: LEB number of LPT's save table (big model only)
+ * @lsave_offs: offset of LPT's save table (big model only)
+ * @lscan_lnum: LEB number of last LPT scan
+ * @empty_lebs: number of empty logical eraseblocks
+ * @idx_lebs: number of indexing logical eraseblocks
+ * @leb_cnt: count of LEBs used by file-system
+ * @padding: reserved for future, zeroes
+ */
+struct ubifs_mst_node {
+ struct ubifs_ch ch;
+ __le64 highest_inum;
+ __le64 cmt_no;
+ __le32 flags;
+ __le32 log_lnum;
+ __le32 root_lnum;
+ __le32 root_offs;
+ __le32 root_len;
+ __le32 gc_lnum;
+ __le32 ihead_lnum;
+ __le32 ihead_offs;
+ __le64 index_size;
+ __le64 total_free;
+ __le64 total_dirty;
+ __le64 total_used;
+ __le64 total_dead;
+ __le64 total_dark;
+ __le32 lpt_lnum;
+ __le32 lpt_offs;
+ __le32 nhead_lnum;
+ __le32 nhead_offs;
+ __le32 ltab_lnum;
+ __le32 ltab_offs;
+ __le32 lsave_lnum;
+ __le32 lsave_offs;
+ __le32 lscan_lnum;
+ __le32 empty_lebs;
+ __le32 idx_lebs;
+ __le32 leb_cnt;
+ __u8 padding[344];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_ref_node - logical eraseblock reference node.
+ * @ch: common header
+ * @lnum: the referred logical eraseblock number
+ * @offs: start offset in the referred LEB
+ * @jhead: journal head number
+ * @padding: reserved for future, zeroes
+ */
+struct ubifs_ref_node {
+ struct ubifs_ch ch;
+ __le32 lnum;
+ __le32 offs;
+ __le32 jhead;
+ __u8 padding[28];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_branch - key/reference/length branch
+ * @lnum: LEB number of the target node
+ * @offs: offset within @lnum
+ * @len: target node length
+ * @key: key
+ */
+struct ubifs_branch {
+ __le32 lnum;
+ __le32 offs;
+ __le32 len;
+ __u8 key[];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_idx_node - indexing node.
+ * @ch: common header
+ * @child_cnt: number of child index nodes
+ * @level: tree level
+ * @branches: LEB number / offset / length / key branches
+ */
+struct ubifs_idx_node {
+ struct ubifs_ch ch;
+ __le16 child_cnt;
+ __le16 level;
+ __u8 branches[];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_cs_node - commit start node.
+ * @ch: common header
+ * @cmt_no: commit number
+ */
+struct ubifs_cs_node {
+ struct ubifs_ch ch;
+ __le64 cmt_no;
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_orph_node - orphan node.
+ * @ch: common header
+ * @cmt_no: commit number (also top bit is set on the last node of the commit)
+ * @inos: inode numbers of orphans
+ */
+struct ubifs_orph_node {
+ struct ubifs_ch ch;
+ __le64 cmt_no;
+ __le64 inos[];
+} __attribute__ ((packed));
+
+#endif /* __UBIFS_MEDIA_H__ */
diff --git a/fs/ubifs/ubifs.c b/fs/ubifs/ubifs.c
new file mode 100644
index 0000000..32f9ff8
--- /dev/null
+++ b/fs/ubifs/ubifs.c
@@ -0,0 +1,687 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * (C) Copyright 2008-2009
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Ðртём)
+ * Adrian Hunter
+ */
+
+#include "ubifs.h"
+
+#if !defined(CONFIG_SYS_64BIT_VSPRINTF)
+#warning Please define CONFIG_SYS_64BIT_VSPRINTF for correct output!
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* compress.c */
+
+/*
+ * We need a wrapper for gunzip() because the parameters are
+ * incompatible with the lzo decompressor.
+ */
+static int gzip_decompress(const unsigned char *in, size_t in_len,
+ unsigned char *out, size_t *out_len)
+{
+ unsigned long len = in_len;
+ return gunzip(out, *out_len, (unsigned char *)in, &len);
+}
+
+/* Fake description object for the "none" compressor */
+static struct ubifs_compressor none_compr = {
+ .compr_type = UBIFS_COMPR_NONE,
+ .name = "no compression",
+ .capi_name = "",
+ .decompress = NULL,
+};
+
+static struct ubifs_compressor lzo_compr = {
+ .compr_type = UBIFS_COMPR_LZO,
+ .name = "LZO",
+ .capi_name = "lzo",
+ .decompress = lzo1x_decompress_safe,
+};
+
+static struct ubifs_compressor zlib_compr = {
+ .compr_type = UBIFS_COMPR_ZLIB,
+ .name = "zlib",
+ .capi_name = "deflate",
+ .decompress = gzip_decompress,
+};
+
+/* All UBIFS compressors */
+struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
+
+/**
+ * ubifs_decompress - decompress data.
+ * @in_buf: data to decompress
+ * @in_len: length of the data to decompress
+ * @out_buf: output buffer where decompressed data should
+ * @out_len: output length is returned here
+ * @compr_type: type of compression
+ *
+ * This function decompresses data from buffer @in_buf into buffer @out_buf.
+ * The length of the uncompressed data is returned in @out_len. This functions
+ * returns %0 on success or a negative error code on failure.
+ */
+int ubifs_decompress(const void *in_buf, int in_len, void *out_buf,
+ int *out_len, int compr_type)
+{
+ int err;
+ struct ubifs_compressor *compr;
+
+ if (unlikely(compr_type < 0 || compr_type >= UBIFS_COMPR_TYPES_CNT)) {
+ ubifs_err("invalid compression type %d", compr_type);
+ return -EINVAL;
+ }
+
+ compr = ubifs_compressors[compr_type];
+
+ if (unlikely(!compr->capi_name)) {
+ ubifs_err("%s compression is not compiled in", compr->name);
+ return -EINVAL;
+ }
+
+ if (compr_type == UBIFS_COMPR_NONE) {
+ memcpy(out_buf, in_buf, in_len);
+ *out_len = in_len;
+ return 0;
+ }
+
+ err = compr->decompress(in_buf, in_len, out_buf, (size_t *)out_len);
+ if (err)
+ ubifs_err("cannot decompress %d bytes, compressor %s, "
+ "error %d", in_len, compr->name, err);
+
+ return err;
+}
+
+/**
+ * compr_init - initialize a compressor.
+ * @compr: compressor description object
+ *
+ * This function initializes the requested compressor and returns zero in case
+ * of success or a negative error code in case of failure.
+ */
+static int __init compr_init(struct ubifs_compressor *compr)
+{
+ ubifs_compressors[compr->compr_type] = compr;
+ ubifs_compressors[compr->compr_type]->name += gd->reloc_off;
+ ubifs_compressors[compr->compr_type]->capi_name += gd->reloc_off;
+ ubifs_compressors[compr->compr_type]->decompress += gd->reloc_off;
+ return 0;
+}
+
+/**
+ * ubifs_compressors_init - initialize UBIFS compressors.
+ *
+ * This function initializes the compressor which were compiled in. Returns
+ * zero in case of success and a negative error code in case of failure.
+ */
+int __init ubifs_compressors_init(void)
+{
+ int err;
+
+ err = compr_init(&lzo_compr);
+ if (err)
+ return err;
+
+ err = compr_init(&zlib_compr);
+ if (err)
+ return err;
+
+ err = compr_init(&none_compr);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+/*
+ * ubifsls...
+ */
+
+static int filldir(struct ubifs_info *c, const char *name, int namlen,
+ u64 ino, unsigned int d_type)
+{
+ struct inode *inode;
+ char filetime[32];
+
+ switch (d_type) {
+ case UBIFS_ITYPE_REG:
+ printf("\t");
+ break;
+ case UBIFS_ITYPE_DIR:
+ printf("<DIR>\t");
+ break;
+ case UBIFS_ITYPE_LNK:
+ printf("<LNK>\t");
+ break;
+ default:
+ printf("other\t");
+ break;
+ }
+
+ inode = ubifs_iget(c->vfs_sb, ino);
+ if (IS_ERR(inode)) {
+ printf("%s: Error in ubifs_iget(), ino=%lld ret=%p!\n",
+ __func__, ino, inode);
+ return -1;
+ }
+ ctime_r((time_t *)&inode->i_mtime, filetime);
+ printf("%9lld %24.24s ", inode->i_size, filetime);
+ ubifs_iput(inode);
+
+ printf("%s\n", name);
+
+ return 0;
+}
+
+static int ubifs_printdir(struct file *file, void *dirent)
+{
+ int err, over = 0;
+ struct qstr nm;
+ union ubifs_key key;
+ struct ubifs_dent_node *dent;
+ struct inode *dir = file->f_path.dentry->d_inode;
+ struct ubifs_info *c = dir->i_sb->s_fs_info;
+
+ dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos);
+
+ if (file->f_pos > UBIFS_S_KEY_HASH_MASK || file->f_pos == 2)
+ /*
+ * The directory was seek'ed to a senseless position or there
+ * are no more entries.
+ */
+ return 0;
+
+ if (file->f_pos == 1) {
+ /* Find the first entry in TNC and save it */
+ lowest_dent_key(c, &key, dir->i_ino);
+ nm.name = NULL;
+ dent = ubifs_tnc_next_ent(c, &key, &nm);
+ if (IS_ERR(dent)) {
+ err = PTR_ERR(dent);
+ goto out;
+ }
+
+ file->f_pos = key_hash_flash(c, &dent->key);
+ file->private_data = dent;
+ }
+
+ dent = file->private_data;
+ if (!dent) {
+ /*
+ * The directory was seek'ed to and is now readdir'ed.
+ * Find the entry corresponding to @file->f_pos or the
+ * closest one.
+ */
+ dent_key_init_hash(c, &key, dir->i_ino, file->f_pos);
+ nm.name = NULL;
+ dent = ubifs_tnc_next_ent(c, &key, &nm);
+ if (IS_ERR(dent)) {
+ err = PTR_ERR(dent);
+ goto out;
+ }
+ file->f_pos = key_hash_flash(c, &dent->key);
+ file->private_data = dent;
+ }
+
+ while (1) {
+ dbg_gen("feed '%s', ino %llu, new f_pos %#x",
+ dent->name, (unsigned long long)le64_to_cpu(dent->inum),
+ key_hash_flash(c, &dent->key));
+ ubifs_assert(le64_to_cpu(dent->ch.sqnum) > ubifs_inode(dir)->creat_sqnum);
+
+ nm.len = le16_to_cpu(dent->nlen);
+ over = filldir(c, (char *)dent->name, nm.len,
+ le64_to_cpu(dent->inum), dent->type);
+ if (over)
+ return 0;
+
+ /* Switch to the next entry */
+ key_read(c, &dent->key, &key);
+ nm.name = (char *)dent->name;
+ dent = ubifs_tnc_next_ent(c, &key, &nm);
+ if (IS_ERR(dent)) {
+ err = PTR_ERR(dent);
+ goto out;
+ }
+
+ kfree(file->private_data);
+ file->f_pos = key_hash_flash(c, &dent->key);
+ file->private_data = dent;
+ cond_resched();
+ }
+
+out:
+ if (err != -ENOENT) {
+ ubifs_err("cannot find next direntry, error %d", err);
+ return err;
+ }
+
+ kfree(file->private_data);
+ file->private_data = NULL;
+ file->f_pos = 2;
+ return 0;
+}
+
+static int ubifs_finddir(struct super_block *sb, char *dirname,
+ unsigned long root_inum, unsigned long *inum)
+{
+ int err;
+ struct qstr nm;
+ union ubifs_key key;
+ struct ubifs_dent_node *dent;
+ struct ubifs_info *c;
+ struct file *file;
+ struct dentry *dentry;
+ struct inode *dir;
+
+ file = kzalloc(sizeof(struct file), 0);
+ dentry = kzalloc(sizeof(struct dentry), 0);
+ dir = kzalloc(sizeof(struct inode), 0);
+ if (!file || !dentry || !dir) {
+ printf("%s: Error, no memory for malloc!\n", __func__);
+ err = -ENOMEM;
+ goto out;
+ }
+
+ dir->i_sb = sb;
+ file->f_path.dentry = dentry;
+ file->f_path.dentry->d_parent = dentry;
+ file->f_path.dentry->d_inode = dir;
+ file->f_path.dentry->d_inode->i_ino = root_inum;
+ c = sb->s_fs_info;
+
+ dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos);
+
+ /* Find the first entry in TNC and save it */
+ lowest_dent_key(c, &key, dir->i_ino);
+ nm.name = NULL;
+ dent = ubifs_tnc_next_ent(c, &key, &nm);
+ if (IS_ERR(dent)) {
+ err = PTR_ERR(dent);
+ goto out;
+ }
+
+ file->f_pos = key_hash_flash(c, &dent->key);
+ file->private_data = dent;
+
+ while (1) {
+ dbg_gen("feed '%s', ino %llu, new f_pos %#x",
+ dent->name, (unsigned long long)le64_to_cpu(dent->inum),
+ key_hash_flash(c, &dent->key));
+ ubifs_assert(le64_to_cpu(dent->ch.sqnum) > ubifs_inode(dir)->creat_sqnum);
+
+ nm.len = le16_to_cpu(dent->nlen);
+ if ((strncmp(dirname, (char *)dent->name, nm.len) == 0) &&
+ (strlen(dirname) == nm.len)) {
+ *inum = le64_to_cpu(dent->inum);
+ return 1;
+ }
+
+ /* Switch to the next entry */
+ key_read(c, &dent->key, &key);
+ nm.name = (char *)dent->name;
+ dent = ubifs_tnc_next_ent(c, &key, &nm);
+ if (IS_ERR(dent)) {
+ err = PTR_ERR(dent);
+ goto out;
+ }
+
+ kfree(file->private_data);
+ file->f_pos = key_hash_flash(c, &dent->key);
+ file->private_data = dent;
+ cond_resched();
+ }
+
+out:
+ if (err != -ENOENT) {
+ ubifs_err("cannot find next direntry, error %d", err);
+ return err;
+ }
+
+ if (file)
+ free(file);
+ if (dentry)
+ free(dentry);
+ if (dir)
+ free(dir);
+
+ if (file->private_data)
+ kfree(file->private_data);
+ file->private_data = NULL;
+ file->f_pos = 2;
+ return 0;
+}
+
+static unsigned long ubifs_findfile(struct super_block *sb, char *filename)
+{
+ int ret;
+ char *next;
+ char fpath[128];
+ char *name = fpath;
+ unsigned long root_inum = 1;
+ unsigned long inum;
+
+ strcpy(fpath, filename);
+
+ /* Remove all leading slashes */
+ while (*name == '/')
+ name++;
+
+ /*
+ * Handle root-direcoty ('/')
+ */
+ inum = root_inum;
+ if (!name || *name == '\0')
+ return inum;
+
+ for (;;) {
+ /* Extract the actual part from the pathname. */
+ next = strchr(name, '/');
+ if (next) {
+ /* Remove all leading slashes. */
+ while (*next == '/')
+ *(next++) = '\0';
+ }
+
+ ret = ubifs_finddir(sb, name, root_inum, &inum);
+
+ /*
+ * Check if directory with this name exists
+ */
+
+ /* Found the node! */
+ if (!next || *next == '\0') {
+ if (ret)
+ return inum;
+
+ break;
+ }
+
+ root_inum = inum;
+ name = next;
+ }
+
+ return 0;
+}
+
+int ubifs_ls(char *filename)
+{
+ struct ubifs_info *c = ubifs_sb->s_fs_info;
+ struct file *file;
+ struct dentry *dentry;
+ struct inode *dir;
+ void *dirent = NULL;
+ unsigned long inum;
+ int ret = 0;
+
+ c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
+ inum = ubifs_findfile(ubifs_sb, filename);
+ if (!inum) {
+ ret = -1;
+ goto out;
+ }
+
+ file = kzalloc(sizeof(struct file), 0);
+ dentry = kzalloc(sizeof(struct dentry), 0);
+ dir = kzalloc(sizeof(struct inode), 0);
+ if (!file || !dentry || !dir) {
+ printf("%s: Error, no memory for malloc!\n", __func__);
+ ret = -ENOMEM;
+ goto out_mem;
+ }
+
+ dir->i_sb = ubifs_sb;
+ file->f_path.dentry = dentry;
+ file->f_path.dentry->d_parent = dentry;
+ file->f_path.dentry->d_inode = dir;
+ file->f_path.dentry->d_inode->i_ino = inum;
+ file->f_pos = 1;
+ file->private_data = NULL;
+ ubifs_printdir(file, dirent);
+
+out_mem:
+ if (file)
+ free(file);
+ if (dentry)
+ free(dentry);
+ if (dir)
+ free(dir);
+
+out:
+ ubi_close_volume(c->ubi);
+ return ret;
+}
+
+/*
+ * ubifsload...
+ */
+
+/* file.c */
+
+static inline void *kmap(struct page *page)
+{
+ return page->addr;
+}
+
+static int read_block(struct inode *inode, void *addr, unsigned int block,
+ struct ubifs_data_node *dn)
+{
+ struct ubifs_info *c = inode->i_sb->s_fs_info;
+ int err, len, out_len;
+ union ubifs_key key;
+ unsigned int dlen;
+
+ data_key_init(c, &key, inode->i_ino, block);
+ err = ubifs_tnc_lookup(c, &key, dn);
+ if (err) {
+ if (err == -ENOENT)
+ /* Not found, so it must be a hole */
+ memset(addr, 0, UBIFS_BLOCK_SIZE);
+ return err;
+ }
+
+ ubifs_assert(le64_to_cpu(dn->ch.sqnum) > ubifs_inode(inode)->creat_sqnum);
+
+ len = le32_to_cpu(dn->size);
+ if (len <= 0 || len > UBIFS_BLOCK_SIZE)
+ goto dump;
+
+ dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
+ out_len = UBIFS_BLOCK_SIZE;
+ err = ubifs_decompress(&dn->data, dlen, addr, &out_len,
+ le16_to_cpu(dn->compr_type));
+ if (err || len != out_len)
+ goto dump;
+
+ /*
+ * Data length can be less than a full block, even for blocks that are
+ * not the last in the file (e.g., as a result of making a hole and
+ * appending data). Ensure that the remainder is zeroed out.
+ */
+ if (len < UBIFS_BLOCK_SIZE)
+ memset(addr + len, 0, UBIFS_BLOCK_SIZE - len);
+
+ return 0;
+
+dump:
+ ubifs_err("bad data node (block %u, inode %lu)",
+ block, inode->i_ino);
+ dbg_dump_node(c, dn);
+ return -EINVAL;
+}
+
+static int do_readpage(struct ubifs_info *c, struct inode *inode, struct page *page)
+{
+ void *addr;
+ int err = 0, i;
+ unsigned int block, beyond;
+ struct ubifs_data_node *dn;
+ loff_t i_size = inode->i_size;
+
+ dbg_gen("ino %lu, pg %lu, i_size %lld",
+ inode->i_ino, page->index, i_size);
+
+ addr = kmap(page);
+
+ block = page->index << UBIFS_BLOCKS_PER_PAGE_SHIFT;
+ beyond = (i_size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
+ if (block >= beyond) {
+ /* Reading beyond inode */
+ memset(addr, 0, PAGE_CACHE_SIZE);
+ goto out;
+ }
+
+ dn = kmalloc(UBIFS_MAX_DATA_NODE_SZ, GFP_NOFS);
+ if (!dn) {
+ err = -ENOMEM;
+ goto error;
+ }
+
+ i = 0;
+ while (1) {
+ int ret;
+
+ if (block >= beyond) {
+ /* Reading beyond inode */
+ err = -ENOENT;
+ memset(addr, 0, UBIFS_BLOCK_SIZE);
+ } else {
+ ret = read_block(inode, addr, block, dn);
+ if (ret) {
+ err = ret;
+ if (err != -ENOENT)
+ break;
+ } else if (block + 1 == beyond) {
+ int dlen = le32_to_cpu(dn->size);
+ int ilen = i_size & (UBIFS_BLOCK_SIZE - 1);
+
+ if (ilen && ilen < dlen)
+ memset(addr + ilen, 0, dlen - ilen);
+ }
+ }
+ if (++i >= UBIFS_BLOCKS_PER_PAGE)
+ break;
+ block += 1;
+ addr += UBIFS_BLOCK_SIZE;
+ }
+ if (err) {
+ if (err == -ENOENT) {
+ /* Not found, so it must be a hole */
+ dbg_gen("hole");
+ goto out_free;
+ }
+ ubifs_err("cannot read page %lu of inode %lu, error %d",
+ page->index, inode->i_ino, err);
+ goto error;
+ }
+
+out_free:
+ kfree(dn);
+out:
+ return 0;
+
+error:
+ kfree(dn);
+ return err;
+}
+
+int ubifs_load(char *filename, u32 addr, u32 size)
+{
+ struct ubifs_info *c = ubifs_sb->s_fs_info;
+ unsigned long inum;
+ struct inode *inode;
+ struct page page;
+ int err = 0;
+ int i;
+ int count;
+ char link_name[64];
+ struct ubifs_inode *ui;
+
+ c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
+ inum = ubifs_findfile(ubifs_sb, filename);
+ if (!inum) {
+ err = -1;
+ goto out;
+ }
+
+ /*
+ * Read file inode
+ */
+ inode = ubifs_iget(ubifs_sb, inum);
+ if (IS_ERR(inode)) {
+ printf("%s: Error reading inode %ld!\n", __func__, inum);
+ err = PTR_ERR(inode);
+ goto out;
+ }
+
+ /*
+ * Check for symbolic link
+ */
+ ui = ubifs_inode(inode);
+ if (((inode->i_mode & S_IFMT) == S_IFLNK) && ui->data_len) {
+ memcpy(link_name, ui->data, ui->data_len);
+ printf("%s is linked to %s!\n", filename, link_name);
+ ubifs_iput(inode);
+
+ /*
+ * Now we have the "real" filename, call ubifs_load()
+ * again (recursive call) to load this file instead
+ */
+ return ubifs_load(link_name, addr, size);
+ }
+
+ /*
+ * If no size was specified or if size bigger than filesize
+ * set size to filesize
+ */
+ if ((size == 0) || (size > inode->i_size))
+ size = inode->i_size;
+
+ count = (size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
+ printf("Loading file '%s' to addr 0x%08x with size %d (0x%08x)...\n",
+ filename, addr, size, size);
+
+ page.addr = (void *)addr;
+ page.index = 0;
+ page.inode = inode;
+ for (i = 0; i < count; i++) {
+ err = do_readpage(c, inode, &page);
+ if (err)
+ break;
+
+ page.addr += PAGE_SIZE;
+ page.index++;
+ }
+
+ if (err)
+ printf("Error reading file '%s'\n", filename);
+ else
+ printf("Done\n");
+
+ ubifs_iput(inode);
+
+out:
+ ubi_close_volume(c->ubi);
+ return err;
+}
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
new file mode 100644
index 0000000..f342dd8
--- /dev/null
+++ b/fs/ubifs/ubifs.h
@@ -0,0 +1,2173 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * (C) Copyright 2008-2009
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Ðртём)
+ * Adrian Hunter
+ */
+
+#ifndef __UBIFS_H__
+#define __UBIFS_H__
+
+#if 0 /* Enable for debugging output */
+#define CONFIG_UBIFS_FS_DEBUG
+#define CONFIG_UBIFS_FS_DEBUG_MSG_LVL 3
+#endif
+
+#include <ubi_uboot.h>
+#include <linux/ctype.h>
+#include <linux/time.h>
+#include <linux/math64.h>
+#include "ubifs-media.h"
+
+struct dentry;
+struct file;
+struct iattr;
+struct kstat;
+struct vfsmount;
+
+extern struct super_block *ubifs_sb;
+
+extern unsigned int ubifs_msg_flags;
+extern unsigned int ubifs_chk_flags;
+extern unsigned int ubifs_tst_flags;
+
+#define pgoff_t unsigned long
+
+/*
+ * We "simulate" the Linux page struct much simpler here
+ */
+struct page {
+ pgoff_t index;
+ void *addr;
+ struct inode *inode;
+};
+
+void iput(struct inode *inode);
+
+/*
+ * The atomic operations are used for budgeting etc which is not
+ * needed for the read-only U-Boot implementation:
+ */
+#define atomic_long_inc(a)
+#define atomic_long_dec(a)
+#define atomic_long_sub(a, b)
+
+/* linux/include/time.h */
+
+struct timespec {
+ time_t tv_sec; /* seconds */
+ long tv_nsec; /* nanoseconds */
+};
+
+/* linux/include/dcache.h */
+
+/*
+ * "quick string" -- eases parameter passing, but more importantly
+ * saves "metadata" about the string (ie length and the hash).
+ *
+ * hash comes first so it snuggles against d_parent in the
+ * dentry.
+ */
+struct qstr {
+ unsigned int hash;
+ unsigned int len;
+ const char *name;
+};
+
+struct inode {
+ struct hlist_node i_hash;
+ struct list_head i_list;
+ struct list_head i_sb_list;
+ struct list_head i_dentry;
+ unsigned long i_ino;
+ unsigned int i_nlink;
+ uid_t i_uid;
+ gid_t i_gid;
+ dev_t i_rdev;
+ u64 i_version;
+ loff_t i_size;
+#ifdef __NEED_I_SIZE_ORDERED
+ seqcount_t i_size_seqcount;
+#endif
+ struct timespec i_atime;
+ struct timespec i_mtime;
+ struct timespec i_ctime;
+ unsigned int i_blkbits;
+ unsigned short i_bytes;
+ umode_t i_mode;
+ spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */
+ struct mutex i_mutex;
+ struct rw_semaphore i_alloc_sem;
+ const struct inode_operations *i_op;
+ const struct file_operations *i_fop; /* former ->i_op->default_file_ops */
+ struct super_block *i_sb;
+ struct file_lock *i_flock;
+#ifdef CONFIG_QUOTA
+ struct dquot *i_dquot[MAXQUOTAS];
+#endif
+ struct list_head i_devices;
+ int i_cindex;
+
+ __u32 i_generation;
+
+#ifdef CONFIG_DNOTIFY
+ unsigned long i_dnotify_mask; /* Directory notify events */
+ struct dnotify_struct *i_dnotify; /* for directory notifications */
+#endif
+
+#ifdef CONFIG_INOTIFY
+ struct list_head inotify_watches; /* watches on this inode */
+ struct mutex inotify_mutex; /* protects the watches list */
+#endif
+
+ unsigned long i_state;
+ unsigned long dirtied_when; /* jiffies of first dirtying */
+
+ unsigned int i_flags;
+
+#ifdef CONFIG_SECURITY
+ void *i_security;
+#endif
+ void *i_private; /* fs or device private pointer */
+};
+
+struct super_block {
+ struct list_head s_list; /* Keep this first */
+ dev_t s_dev; /* search index; _not_ kdev_t */
+ unsigned long s_blocksize;
+ unsigned char s_blocksize_bits;
+ unsigned char s_dirt;
+ unsigned long long s_maxbytes; /* Max file size */
+ struct file_system_type *s_type;
+ const struct super_operations *s_op;
+ struct dquot_operations *dq_op;
+ struct quotactl_ops *s_qcop;
+ const struct export_operations *s_export_op;
+ unsigned long s_flags;
+ unsigned long s_magic;
+ struct dentry *s_root;
+ struct rw_semaphore s_umount;
+ struct mutex s_lock;
+ int s_count;
+ int s_syncing;
+ int s_need_sync_fs;
+#ifdef CONFIG_SECURITY
+ void *s_security;
+#endif
+ struct xattr_handler **s_xattr;
+
+ struct list_head s_inodes; /* all inodes */
+ struct list_head s_dirty; /* dirty inodes */
+ struct list_head s_io; /* parked for writeback */
+ struct list_head s_more_io; /* parked for more writeback */
+ struct hlist_head s_anon; /* anonymous dentries for (nfs) exporting */
+ struct list_head s_files;
+ /* s_dentry_lru and s_nr_dentry_unused are protected by dcache_lock */
+ struct list_head s_dentry_lru; /* unused dentry lru */
+ int s_nr_dentry_unused; /* # of dentry on lru */
+
+ struct block_device *s_bdev;
+ struct mtd_info *s_mtd;
+ struct list_head s_instances;
+
+ int s_frozen;
+ wait_queue_head_t s_wait_unfrozen;
+
+ char s_id[32]; /* Informational name */
+
+ void *s_fs_info; /* Filesystem private info */
+
+ /*
+ * The next field is for VFS *only*. No filesystems have any business
+ * even looking at it. You had been warned.
+ */
+ struct mutex s_vfs_rename_mutex; /* Kludge */
+
+ /* Granularity of c/m/atime in ns.
+ Cannot be worse than a second */
+ u32 s_time_gran;
+
+ /*
+ * Filesystem subtype. If non-empty the filesystem type field
+ * in /proc/mounts will be "type.subtype"
+ */
+ char *s_subtype;
+
+ /*
+ * Saved mount options for lazy filesystems using
+ * generic_show_options()
+ */
+ char *s_options;
+};
+
+struct file_system_type {
+ const char *name;
+ int fs_flags;
+ int (*get_sb) (struct file_system_type *, int,
+ const char *, void *, struct vfsmount *);
+ void (*kill_sb) (struct super_block *);
+ struct module *owner;
+ struct file_system_type * next;
+ struct list_head fs_supers;
+};
+
+struct vfsmount {
+ struct list_head mnt_hash;
+ struct vfsmount *mnt_parent; /* fs we are mounted on */
+ struct dentry *mnt_mountpoint; /* dentry of mountpoint */
+ struct dentry *mnt_root; /* root of the mounted tree */
+ struct super_block *mnt_sb; /* pointer to superblock */
+ struct list_head mnt_mounts; /* list of children, anchored here */
+ struct list_head mnt_child; /* and going through their mnt_child */
+ int mnt_flags;
+ /* 4 bytes hole on 64bits arches */
+ const char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */
+ struct list_head mnt_list;
+ struct list_head mnt_expire; /* link in fs-specific expiry list */
+ struct list_head mnt_share; /* circular list of shared mounts */
+ struct list_head mnt_slave_list;/* list of slave mounts */
+ struct list_head mnt_slave; /* slave list entry */
+ struct vfsmount *mnt_master; /* slave is on master->mnt_slave_list */
+ struct mnt_namespace *mnt_ns; /* containing namespace */
+ int mnt_id; /* mount identifier */
+ int mnt_group_id; /* peer group identifier */
+ /*
+ * We put mnt_count & mnt_expiry_mark at the end of struct vfsmount
+ * to let these frequently modified fields in a separate cache line
+ * (so that reads of mnt_flags wont ping-pong on SMP machines)
+ */
+ int mnt_expiry_mark; /* true if marked for expiry */
+ int mnt_pinned;
+ int mnt_ghosts;
+ /*
+ * This value is not stable unless all of the mnt_writers[] spinlocks
+ * are held, and all mnt_writer[]s on this mount have 0 as their ->count
+ */
+};
+
+struct path {
+ struct vfsmount *mnt;
+ struct dentry *dentry;
+};
+
+struct file {
+ struct path f_path;
+#define f_dentry f_path.dentry
+#define f_vfsmnt f_path.mnt
+ const struct file_operations *f_op;
+ unsigned int f_flags;
+ loff_t f_pos;
+ unsigned int f_uid, f_gid;
+
+ u64 f_version;
+#ifdef CONFIG_SECURITY
+ void *f_security;
+#endif
+ /* needed for tty driver, and maybe others */
+ void *private_data;
+
+#ifdef CONFIG_EPOLL
+ /* Used by fs/eventpoll.c to link all the hooks to this file */
+ struct list_head f_ep_links;
+ spinlock_t f_ep_lock;
+#endif /* #ifdef CONFIG_EPOLL */
+#ifdef CONFIG_DEBUG_WRITECOUNT
+ unsigned long f_mnt_write_state;
+#endif
+};
+
+/*
+ * get_seconds() not really needed in the read-only implmentation
+ */
+#define get_seconds() 0
+
+/* 4k page size */
+#define PAGE_CACHE_SHIFT 12
+#define PAGE_CACHE_SIZE (1 << PAGE_CACHE_SHIFT)
+
+/* Page cache limit. The filesystems should put that into their s_maxbytes
+ limits, otherwise bad things can happen in VM. */
+#if BITS_PER_LONG==32
+#define MAX_LFS_FILESIZE (((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1)
+#elif BITS_PER_LONG==64
+#define MAX_LFS_FILESIZE 0x7fffffffffffffffUL
+#endif
+
+#define INT_MAX ((int)(~0U>>1))
+#define INT_MIN (-INT_MAX - 1)
+#define LLONG_MAX ((long long)(~0ULL>>1))
+
+/*
+ * These are the fs-independent mount-flags: up to 32 flags are supported
+ */
+#define MS_RDONLY 1 /* Mount read-only */
+#define MS_NOSUID 2 /* Ignore suid and sgid bits */
+#define MS_NODEV 4 /* Disallow access to device special files */
+#define MS_NOEXEC 8 /* Disallow program execution */
+#define MS_SYNCHRONOUS 16 /* Writes are synced at once */
+#define MS_REMOUNT 32 /* Alter flags of a mounted FS */
+#define MS_MANDLOCK 64 /* Allow mandatory locks on an FS */
+#define MS_DIRSYNC 128 /* Directory modifications are synchronous */
+#define MS_NOATIME 1024 /* Do not update access times. */
+#define MS_NODIRATIME 2048 /* Do not update directory access times */
+#define MS_BIND 4096
+#define MS_MOVE 8192
+#define MS_REC 16384
+#define MS_VERBOSE 32768 /* War is peace. Verbosity is silence.
+ MS_VERBOSE is deprecated. */
+#define MS_SILENT 32768
+#define MS_POSIXACL (1<<16) /* VFS does not apply the umask */
+#define MS_UNBINDABLE (1<<17) /* change to unbindable */
+#define MS_PRIVATE (1<<18) /* change to private */
+#define MS_SLAVE (1<<19) /* change to slave */
+#define MS_SHARED (1<<20) /* change to shared */
+#define MS_RELATIME (1<<21) /* Update atime relative to mtime/ctime. */
+#define MS_KERNMOUNT (1<<22) /* this is a kern_mount call */
+#define MS_I_VERSION (1<<23) /* Update inode I_version field */
+#define MS_ACTIVE (1<<30)
+#define MS_NOUSER (1<<31)
+
+#define I_NEW 8
+
+/* Inode flags - they have nothing to superblock flags now */
+
+#define S_SYNC 1 /* Writes are synced at once */
+#define S_NOATIME 2 /* Do not update access times */
+#define S_APPEND 4 /* Append-only file */
+#define S_IMMUTABLE 8 /* Immutable file */
+#define S_DEAD 16 /* removed, but still open directory */
+#define S_NOQUOTA 32 /* Inode is not counted to quota */
+#define S_DIRSYNC 64 /* Directory modifications are synchronous */
+#define S_NOCMTIME 128 /* Do not update file c/mtime */
+#define S_SWAPFILE 256 /* Do not truncate: swapon got its bmaps */
+#define S_PRIVATE 512 /* Inode is fs-internal */
+
+/* include/linux/stat.h */
+
+#define S_IFMT 00170000
+#define S_IFSOCK 0140000
+#define S_IFLNK 0120000
+#define S_IFREG 0100000
+#define S_IFBLK 0060000
+#define S_IFDIR 0040000
+#define S_IFCHR 0020000
+#define S_IFIFO 0010000
+#define S_ISUID 0004000
+#define S_ISGID 0002000
+#define S_ISVTX 0001000
+
+/* include/linux/fs.h */
+
+/*
+ * File types
+ *
+ * NOTE! These match bits 12..15 of stat.st_mode
+ * (ie "(i_mode >> 12) & 15").
+ */
+#define DT_UNKNOWN 0
+#define DT_FIFO 1
+#define DT_CHR 2
+#define DT_DIR 4
+#define DT_BLK 6
+#define DT_REG 8
+#define DT_LNK 10
+#define DT_SOCK 12
+#define DT_WHT 14
+
+#define I_DIRTY_SYNC 1
+#define I_DIRTY_DATASYNC 2
+#define I_DIRTY_PAGES 4
+#define I_NEW 8
+#define I_WILL_FREE 16
+#define I_FREEING 32
+#define I_CLEAR 64
+#define __I_LOCK 7
+#define I_LOCK (1 << __I_LOCK)
+#define __I_SYNC 8
+#define I_SYNC (1 << __I_SYNC)
+
+#define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)
+
+/* linux/include/dcache.h */
+
+#define DNAME_INLINE_LEN_MIN 36
+
+struct dentry {
+ unsigned int d_flags; /* protected by d_lock */
+ spinlock_t d_lock; /* per dentry lock */
+ struct inode *d_inode; /* Where the name belongs to - NULL is
+ * negative */
+ /*
+ * The next three fields are touched by __d_lookup. Place them here
+ * so they all fit in a cache line.
+ */
+ struct hlist_node d_hash; /* lookup hash list */
+ struct dentry *d_parent; /* parent directory */
+ struct qstr d_name;
+
+ struct list_head d_lru; /* LRU list */
+ /*
+ * d_child and d_rcu can share memory
+ */
+ struct list_head d_subdirs; /* our children */
+ struct list_head d_alias; /* inode alias list */
+ unsigned long d_time; /* used by d_revalidate */
+ struct super_block *d_sb; /* The root of the dentry tree */
+ void *d_fsdata; /* fs-specific data */
+#ifdef CONFIG_PROFILING
+ struct dcookie_struct *d_cookie; /* cookie, if any */
+#endif
+ int d_mounted;
+ unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */
+};
+
+static inline ino_t parent_ino(struct dentry *dentry)
+{
+ ino_t res;
+
+ spin_lock(&dentry->d_lock);
+ res = dentry->d_parent->d_inode->i_ino;
+ spin_unlock(&dentry->d_lock);
+ return res;
+}
+
+/* linux/include/linux/bitops.h */
+
+#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
+#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
+
+/* linux/include/asm-generic/bitops/non-atomic.h */
+
+/**
+ * __set_bit - Set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * Unlike set_bit(), this function is non-atomic and may be reordered.
+ * If it's called on the same region of memory simultaneously, the effect
+ * may be that only one operation succeeds.
+ */
+static inline void __set_bit(int nr, volatile unsigned long *addr)
+{
+ unsigned long mask = BIT_MASK(nr);
+ unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+
+ *p |= mask;
+}
+
+static inline void __clear_bit(int nr, volatile unsigned long *addr)
+{
+ unsigned long mask = BIT_MASK(nr);
+ unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+
+ *p &= ~mask;
+}
+
+/* debug.c */
+
+#define DEFINE_SPINLOCK(...)
+#define module_param_named(...)
+
+/* misc.h */
+#define mutex_lock_nested(...)
+#define mutex_unlock_nested(...)
+#define mutex_is_locked(...) 0
+
+/* Version of this UBIFS implementation */
+#define UBIFS_VERSION 1
+
+/* Normal UBIFS messages */
+#define ubifs_msg(fmt, ...) \
+ printk(KERN_NOTICE "UBIFS: " fmt "\n", ##__VA_ARGS__)
+/* UBIFS error messages */
+#define ubifs_err(fmt, ...) \
+ printk(KERN_ERR "UBIFS error (pid %d): %s: " fmt "\n", 0, \
+ __func__, ##__VA_ARGS__)
+/* UBIFS warning messages */
+#define ubifs_warn(fmt, ...) \
+ printk(KERN_WARNING "UBIFS warning (pid %d): %s: " fmt "\n", \
+ 0, __func__, ##__VA_ARGS__)
+
+/* UBIFS file system VFS magic number */
+#define UBIFS_SUPER_MAGIC 0x24051905
+
+/* Number of UBIFS blocks per VFS page */
+#define UBIFS_BLOCKS_PER_PAGE (PAGE_CACHE_SIZE / UBIFS_BLOCK_SIZE)
+#define UBIFS_BLOCKS_PER_PAGE_SHIFT (PAGE_CACHE_SHIFT - UBIFS_BLOCK_SHIFT)
+
+/* "File system end of life" sequence number watermark */
+#define SQNUM_WARN_WATERMARK 0xFFFFFFFF00000000ULL
+#define SQNUM_WATERMARK 0xFFFFFFFFFF000000ULL
+
+/*
+ * Minimum amount of LEBs reserved for the index. At present the index needs at
+ * least 2 LEBs: one for the index head and one for in-the-gaps method (which
+ * currently does not cater for the index head and so excludes it from
+ * consideration).
+ */
+#define MIN_INDEX_LEBS 2
+
+/* Minimum amount of data UBIFS writes to the flash */
+#define MIN_WRITE_SZ (UBIFS_DATA_NODE_SZ + 8)
+
+/*
+ * Currently we do not support inode number overlapping and re-using, so this
+ * watermark defines dangerous inode number level. This should be fixed later,
+ * although it is difficult to exceed current limit. Another option is to use
+ * 64-bit inode numbers, but this means more overhead.
+ */
+#define INUM_WARN_WATERMARK 0xFFF00000
+#define INUM_WATERMARK 0xFFFFFF00
+
+/* Largest key size supported in this implementation */
+#define CUR_MAX_KEY_LEN UBIFS_SK_LEN
+
+/* Maximum number of entries in each LPT (LEB category) heap */
+#define LPT_HEAP_SZ 256
+
+/*
+ * Background thread name pattern. The numbers are UBI device and volume
+ * numbers.
+ */
+#define BGT_NAME_PATTERN "ubifs_bgt%d_%d"
+
+/* Default write-buffer synchronization timeout (5 secs) */
+#define DEFAULT_WBUF_TIMEOUT (5 * HZ)
+
+/* Maximum possible inode number (only 32-bit inodes are supported now) */
+#define MAX_INUM 0xFFFFFFFF
+
+/* Number of non-data journal heads */
+#define NONDATA_JHEADS_CNT 2
+
+/* Garbage collector head */
+#define GCHD 0
+/* Base journal head number */
+#define BASEHD 1
+/* First "general purpose" journal head */
+#define DATAHD 2
+
+/* 'No change' value for 'ubifs_change_lp()' */
+#define LPROPS_NC 0x80000001
+
+/*
+ * There is no notion of truncation key because truncation nodes do not exist
+ * in TNC. However, when replaying, it is handy to introduce fake "truncation"
+ * keys for truncation nodes because the code becomes simpler. So we define
+ * %UBIFS_TRUN_KEY type.
+ */
+#define UBIFS_TRUN_KEY UBIFS_KEY_TYPES_CNT
+
+/*
+ * How much a directory entry/extended attribute entry adds to the parent/host
+ * inode.
+ */
+#define CALC_DENT_SIZE(name_len) ALIGN(UBIFS_DENT_NODE_SZ + (name_len) + 1, 8)
+
+/* How much an extended attribute adds to the host inode */
+#define CALC_XATTR_BYTES(data_len) ALIGN(UBIFS_INO_NODE_SZ + (data_len) + 1, 8)
+
+/*
+ * Znodes which were not touched for 'OLD_ZNODE_AGE' seconds are considered
+ * "old", and znode which were touched last 'YOUNG_ZNODE_AGE' seconds ago are
+ * considered "young". This is used by shrinker when selecting znode to trim
+ * off.
+ */
+#define OLD_ZNODE_AGE 20
+#define YOUNG_ZNODE_AGE 5
+
+/*
+ * Some compressors, like LZO, may end up with more data then the input buffer.
+ * So UBIFS always allocates larger output buffer, to be sure the compressor
+ * will not corrupt memory in case of worst case compression.
+ */
+#define WORST_COMPR_FACTOR 2
+
+/* Maximum expected tree height for use by bottom_up_buf */
+#define BOTTOM_UP_HEIGHT 64
+
+/* Maximum number of data nodes to bulk-read */
+#define UBIFS_MAX_BULK_READ 32
+
+/*
+ * Lockdep classes for UBIFS inode @ui_mutex.
+ */
+enum {
+ WB_MUTEX_1 = 0,
+ WB_MUTEX_2 = 1,
+ WB_MUTEX_3 = 2,
+};
+
+/*
+ * Znode flags (actually, bit numbers which store the flags).
+ *
+ * DIRTY_ZNODE: znode is dirty
+ * COW_ZNODE: znode is being committed and a new instance of this znode has to
+ * be created before changing this znode
+ * OBSOLETE_ZNODE: znode is obsolete, which means it was deleted, but it is
+ * still in the commit list and the ongoing commit operation
+ * will commit it, and delete this znode after it is done
+ */
+enum {
+ DIRTY_ZNODE = 0,
+ COW_ZNODE = 1,
+ OBSOLETE_ZNODE = 2,
+};
+
+/*
+ * Commit states.
+ *
+ * COMMIT_RESTING: commit is not wanted
+ * COMMIT_BACKGROUND: background commit has been requested
+ * COMMIT_REQUIRED: commit is required
+ * COMMIT_RUNNING_BACKGROUND: background commit is running
+ * COMMIT_RUNNING_REQUIRED: commit is running and it is required
+ * COMMIT_BROKEN: commit failed
+ */
+enum {
+ COMMIT_RESTING = 0,
+ COMMIT_BACKGROUND,
+ COMMIT_REQUIRED,
+ COMMIT_RUNNING_BACKGROUND,
+ COMMIT_RUNNING_REQUIRED,
+ COMMIT_BROKEN,
+};
+
+/*
+ * 'ubifs_scan_a_node()' return values.
+ *
+ * SCANNED_GARBAGE: scanned garbage
+ * SCANNED_EMPTY_SPACE: scanned empty space
+ * SCANNED_A_NODE: scanned a valid node
+ * SCANNED_A_CORRUPT_NODE: scanned a corrupted node
+ * SCANNED_A_BAD_PAD_NODE: scanned a padding node with invalid pad length
+ *
+ * Greater than zero means: 'scanned that number of padding bytes'
+ */
+enum {
+ SCANNED_GARBAGE = 0,
+ SCANNED_EMPTY_SPACE = -1,
+ SCANNED_A_NODE = -2,
+ SCANNED_A_CORRUPT_NODE = -3,
+ SCANNED_A_BAD_PAD_NODE = -4,
+};
+
+/*
+ * LPT cnode flag bits.
+ *
+ * DIRTY_CNODE: cnode is dirty
+ * COW_CNODE: cnode is being committed and must be copied before writing
+ * OBSOLETE_CNODE: cnode is being committed and has been copied (or deleted),
+ * so it can (and must) be freed when the commit is finished
+ */
+enum {
+ DIRTY_CNODE = 0,
+ COW_CNODE = 1,
+ OBSOLETE_CNODE = 2,
+};
+
+/*
+ * Dirty flag bits (lpt_drty_flgs) for LPT special nodes.
+ *
+ * LTAB_DIRTY: ltab node is dirty
+ * LSAVE_DIRTY: lsave node is dirty
+ */
+enum {
+ LTAB_DIRTY = 1,
+ LSAVE_DIRTY = 2,
+};
+
+/*
+ * Return codes used by the garbage collector.
+ * @LEB_FREED: the logical eraseblock was freed and is ready to use
+ * @LEB_FREED_IDX: indexing LEB was freed and can be used only after the commit
+ * @LEB_RETAINED: the logical eraseblock was freed and retained for GC purposes
+ */
+enum {
+ LEB_FREED,
+ LEB_FREED_IDX,
+ LEB_RETAINED,
+};
+
+/**
+ * struct ubifs_old_idx - index node obsoleted since last commit start.
+ * @rb: rb-tree node
+ * @lnum: LEB number of obsoleted index node
+ * @offs: offset of obsoleted index node
+ */
+struct ubifs_old_idx {
+ struct rb_node rb;
+ int lnum;
+ int offs;
+};
+
+/* The below union makes it easier to deal with keys */
+union ubifs_key {
+ uint8_t u8[CUR_MAX_KEY_LEN];
+ uint32_t u32[CUR_MAX_KEY_LEN/4];
+ uint64_t u64[CUR_MAX_KEY_LEN/8];
+ __le32 j32[CUR_MAX_KEY_LEN/4];
+};
+
+/**
+ * struct ubifs_scan_node - UBIFS scanned node information.
+ * @list: list of scanned nodes
+ * @key: key of node scanned (if it has one)
+ * @sqnum: sequence number
+ * @type: type of node scanned
+ * @offs: offset with LEB of node scanned
+ * @len: length of node scanned
+ * @node: raw node
+ */
+struct ubifs_scan_node {
+ struct list_head list;
+ union ubifs_key key;
+ unsigned long long sqnum;
+ int type;
+ int offs;
+ int len;
+ void *node;
+};
+
+/**
+ * struct ubifs_scan_leb - UBIFS scanned LEB information.
+ * @lnum: logical eraseblock number
+ * @nodes_cnt: number of nodes scanned
+ * @nodes: list of struct ubifs_scan_node
+ * @endpt: end point (and therefore the start of empty space)
+ * @ecc: read returned -EBADMSG
+ * @buf: buffer containing entire LEB scanned
+ */
+struct ubifs_scan_leb {
+ int lnum;
+ int nodes_cnt;
+ struct list_head nodes;
+ int endpt;
+ int ecc;
+ void *buf;
+};
+
+/**
+ * struct ubifs_gced_idx_leb - garbage-collected indexing LEB.
+ * @list: list
+ * @lnum: LEB number
+ * @unmap: OK to unmap this LEB
+ *
+ * This data structure is used to temporary store garbage-collected indexing
+ * LEBs - they are not released immediately, but only after the next commit.
+ * This is needed to guarantee recoverability.
+ */
+struct ubifs_gced_idx_leb {
+ struct list_head list;
+ int lnum;
+ int unmap;
+};
+
+/**
+ * struct ubifs_inode - UBIFS in-memory inode description.
+ * @vfs_inode: VFS inode description object
+ * @creat_sqnum: sequence number at time of creation
+ * @del_cmtno: commit number corresponding to the time the inode was deleted,
+ * protected by @c->commit_sem;
+ * @xattr_size: summarized size of all extended attributes in bytes
+ * @xattr_cnt: count of extended attributes this inode has
+ * @xattr_names: sum of lengths of all extended attribute names belonging to
+ * this inode
+ * @dirty: non-zero if the inode is dirty
+ * @xattr: non-zero if this is an extended attribute inode
+ * @bulk_read: non-zero if bulk-read should be used
+ * @ui_mutex: serializes inode write-back with the rest of VFS operations,
+ * serializes "clean <-> dirty" state changes, serializes bulk-read,
+ * protects @dirty, @bulk_read, @ui_size, and @xattr_size
+ * @ui_lock: protects @synced_i_size
+ * @synced_i_size: synchronized size of inode, i.e. the value of inode size
+ * currently stored on the flash; used only for regular file
+ * inodes
+ * @ui_size: inode size used by UBIFS when writing to flash
+ * @flags: inode flags (@UBIFS_COMPR_FL, etc)
+ * @compr_type: default compression type used for this inode
+ * @last_page_read: page number of last page read (for bulk read)
+ * @read_in_a_row: number of consecutive pages read in a row (for bulk read)
+ * @data_len: length of the data attached to the inode
+ * @data: inode's data
+ *
+ * @ui_mutex exists for two main reasons. At first it prevents inodes from
+ * being written back while UBIFS changing them, being in the middle of an VFS
+ * operation. This way UBIFS makes sure the inode fields are consistent. For
+ * example, in 'ubifs_rename()' we change 3 inodes simultaneously, and
+ * write-back must not write any of them before we have finished.
+ *
+ * The second reason is budgeting - UBIFS has to budget all operations. If an
+ * operation is going to mark an inode dirty, it has to allocate budget for
+ * this. It cannot just mark it dirty because there is no guarantee there will
+ * be enough flash space to write the inode back later. This means UBIFS has
+ * to have full control over inode "clean <-> dirty" transitions (and pages
+ * actually). But unfortunately, VFS marks inodes dirty in many places, and it
+ * does not ask the file-system if it is allowed to do so (there is a notifier,
+ * but it is not enough), i.e., there is no mechanism to synchronize with this.
+ * So UBIFS has its own inode dirty flag and its own mutex to serialize
+ * "clean <-> dirty" transitions.
+ *
+ * The @synced_i_size field is used to make sure we never write pages which are
+ * beyond last synchronized inode size. See 'ubifs_writepage()' for more
+ * information.
+ *
+ * The @ui_size is a "shadow" variable for @inode->i_size and UBIFS uses
+ * @ui_size instead of @inode->i_size. The reason for this is that UBIFS cannot
+ * make sure @inode->i_size is always changed under @ui_mutex, because it
+ * cannot call 'vmtruncate()' with @ui_mutex locked, because it would deadlock
+ * with 'ubifs_writepage()' (see file.c). All the other inode fields are
+ * changed under @ui_mutex, so they do not need "shadow" fields. Note, one
+ * could consider to rework locking and base it on "shadow" fields.
+ */
+struct ubifs_inode {
+ struct inode vfs_inode;
+ unsigned long long creat_sqnum;
+ unsigned long long del_cmtno;
+ unsigned int xattr_size;
+ unsigned int xattr_cnt;
+ unsigned int xattr_names;
+ unsigned int dirty:1;
+ unsigned int xattr:1;
+ unsigned int bulk_read:1;
+ unsigned int compr_type:2;
+ struct mutex ui_mutex;
+ spinlock_t ui_lock;
+ loff_t synced_i_size;
+ loff_t ui_size;
+ int flags;
+ pgoff_t last_page_read;
+ pgoff_t read_in_a_row;
+ int data_len;
+ void *data;
+};
+
+/**
+ * struct ubifs_unclean_leb - records a LEB recovered under read-only mode.
+ * @list: list
+ * @lnum: LEB number of recovered LEB
+ * @endpt: offset where recovery ended
+ *
+ * This structure records a LEB identified during recovery that needs to be
+ * cleaned but was not because UBIFS was mounted read-only. The information
+ * is used to clean the LEB when remounting to read-write mode.
+ */
+struct ubifs_unclean_leb {
+ struct list_head list;
+ int lnum;
+ int endpt;
+};
+
+/*
+ * LEB properties flags.
+ *
+ * LPROPS_UNCAT: not categorized
+ * LPROPS_DIRTY: dirty > free, dirty >= @c->dead_wm, not index
+ * LPROPS_DIRTY_IDX: dirty + free > @c->min_idx_node_sze and index
+ * LPROPS_FREE: free > 0, dirty < @c->dead_wm, not empty, not index
+ * LPROPS_HEAP_CNT: number of heaps used for storing categorized LEBs
+ * LPROPS_EMPTY: LEB is empty, not taken
+ * LPROPS_FREEABLE: free + dirty == leb_size, not index, not taken
+ * LPROPS_FRDI_IDX: free + dirty == leb_size and index, may be taken
+ * LPROPS_CAT_MASK: mask for the LEB categories above
+ * LPROPS_TAKEN: LEB was taken (this flag is not saved on the media)
+ * LPROPS_INDEX: LEB contains indexing nodes (this flag also exists on flash)
+ */
+enum {
+ LPROPS_UNCAT = 0,
+ LPROPS_DIRTY = 1,
+ LPROPS_DIRTY_IDX = 2,
+ LPROPS_FREE = 3,
+ LPROPS_HEAP_CNT = 3,
+ LPROPS_EMPTY = 4,
+ LPROPS_FREEABLE = 5,
+ LPROPS_FRDI_IDX = 6,
+ LPROPS_CAT_MASK = 15,
+ LPROPS_TAKEN = 16,
+ LPROPS_INDEX = 32,
+};
+
+/**
+ * struct ubifs_lprops - logical eraseblock properties.
+ * @free: amount of free space in bytes
+ * @dirty: amount of dirty space in bytes
+ * @flags: LEB properties flags (see above)
+ * @lnum: LEB number
+ * @list: list of same-category lprops (for LPROPS_EMPTY and LPROPS_FREEABLE)
+ * @hpos: heap position in heap of same-category lprops (other categories)
+ */
+struct ubifs_lprops {
+ int free;
+ int dirty;
+ int flags;
+ int lnum;
+ union {
+ struct list_head list;
+ int hpos;
+ };
+};
+
+/**
+ * struct ubifs_lpt_lprops - LPT logical eraseblock properties.
+ * @free: amount of free space in bytes
+ * @dirty: amount of dirty space in bytes
+ * @tgc: trivial GC flag (1 => unmap after commit end)
+ * @cmt: commit flag (1 => reserved for commit)
+ */
+struct ubifs_lpt_lprops {
+ int free;
+ int dirty;
+ unsigned tgc:1;
+ unsigned cmt:1;
+};
+
+/**
+ * struct ubifs_lp_stats - statistics of eraseblocks in the main area.
+ * @empty_lebs: number of empty LEBs
+ * @taken_empty_lebs: number of taken LEBs
+ * @idx_lebs: number of indexing LEBs
+ * @total_free: total free space in bytes (includes all LEBs)
+ * @total_dirty: total dirty space in bytes (includes all LEBs)
+ * @total_used: total used space in bytes (does not include index LEBs)
+ * @total_dead: total dead space in bytes (does not include index LEBs)
+ * @total_dark: total dark space in bytes (does not include index LEBs)
+ *
+ * The @taken_empty_lebs field counts the LEBs that are in the transient state
+ * of having been "taken" for use but not yet written to. @taken_empty_lebs is
+ * needed to account correctly for @gc_lnum, otherwise @empty_lebs could be
+ * used by itself (in which case 'unused_lebs' would be a better name). In the
+ * case of @gc_lnum, it is "taken" at mount time or whenever a LEB is retained
+ * by GC, but unlike other empty LEBs that are "taken", it may not be written
+ * straight away (i.e. before the next commit start or unmount), so either
+ * @gc_lnum must be specially accounted for, or the current approach followed
+ * i.e. count it under @taken_empty_lebs.
+ *
+ * @empty_lebs includes @taken_empty_lebs.
+ *
+ * @total_used, @total_dead and @total_dark fields do not account indexing
+ * LEBs.
+ */
+struct ubifs_lp_stats {
+ int empty_lebs;
+ int taken_empty_lebs;
+ int idx_lebs;
+ long long total_free;
+ long long total_dirty;
+ long long total_used;
+ long long total_dead;
+ long long total_dark;
+};
+
+struct ubifs_nnode;
+
+/**
+ * struct ubifs_cnode - LEB Properties Tree common node.
+ * @parent: parent nnode
+ * @cnext: next cnode to commit
+ * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE)
+ * @iip: index in parent
+ * @level: level in the tree (zero for pnodes, greater than zero for nnodes)
+ * @num: node number
+ */
+struct ubifs_cnode {
+ struct ubifs_nnode *parent;
+ struct ubifs_cnode *cnext;
+ unsigned long flags;
+ int iip;
+ int level;
+ int num;
+};
+
+/**
+ * struct ubifs_pnode - LEB Properties Tree leaf node.
+ * @parent: parent nnode
+ * @cnext: next cnode to commit
+ * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE)
+ * @iip: index in parent
+ * @level: level in the tree (always zero for pnodes)
+ * @num: node number
+ * @lprops: LEB properties array
+ */
+struct ubifs_pnode {
+ struct ubifs_nnode *parent;
+ struct ubifs_cnode *cnext;
+ unsigned long flags;
+ int iip;
+ int level;
+ int num;
+ struct ubifs_lprops lprops[UBIFS_LPT_FANOUT];
+};
+
+/**
+ * struct ubifs_nbranch - LEB Properties Tree internal node branch.
+ * @lnum: LEB number of child
+ * @offs: offset of child
+ * @nnode: nnode child
+ * @pnode: pnode child
+ * @cnode: cnode child
+ */
+struct ubifs_nbranch {
+ int lnum;
+ int offs;
+ union {
+ struct ubifs_nnode *nnode;
+ struct ubifs_pnode *pnode;
+ struct ubifs_cnode *cnode;
+ };
+};
+
+/**
+ * struct ubifs_nnode - LEB Properties Tree internal node.
+ * @parent: parent nnode
+ * @cnext: next cnode to commit
+ * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE)
+ * @iip: index in parent
+ * @level: level in the tree (always greater than zero for nnodes)
+ * @num: node number
+ * @nbranch: branches to child nodes
+ */
+struct ubifs_nnode {
+ struct ubifs_nnode *parent;
+ struct ubifs_cnode *cnext;
+ unsigned long flags;
+ int iip;
+ int level;
+ int num;
+ struct ubifs_nbranch nbranch[UBIFS_LPT_FANOUT];
+};
+
+/**
+ * struct ubifs_lpt_heap - heap of categorized lprops.
+ * @arr: heap array
+ * @cnt: number in heap
+ * @max_cnt: maximum number allowed in heap
+ *
+ * There are %LPROPS_HEAP_CNT heaps.
+ */
+struct ubifs_lpt_heap {
+ struct ubifs_lprops **arr;
+ int cnt;
+ int max_cnt;
+};
+
+/*
+ * Return codes for LPT scan callback function.
+ *
+ * LPT_SCAN_CONTINUE: continue scanning
+ * LPT_SCAN_ADD: add the LEB properties scanned to the tree in memory
+ * LPT_SCAN_STOP: stop scanning
+ */
+enum {
+ LPT_SCAN_CONTINUE = 0,
+ LPT_SCAN_ADD = 1,
+ LPT_SCAN_STOP = 2,
+};
+
+struct ubifs_info;
+
+/* Callback used by the 'ubifs_lpt_scan_nolock()' function */
+typedef int (*ubifs_lpt_scan_callback)(struct ubifs_info *c,
+ const struct ubifs_lprops *lprops,
+ int in_tree, void *data);
+
+/**
+ * struct ubifs_wbuf - UBIFS write-buffer.
+ * @c: UBIFS file-system description object
+ * @buf: write-buffer (of min. flash I/O unit size)
+ * @lnum: logical eraseblock number the write-buffer points to
+ * @offs: write-buffer offset in this logical eraseblock
+ * @avail: number of bytes available in the write-buffer
+ * @used: number of used bytes in the write-buffer
+ * @dtype: type of data stored in this LEB (%UBI_LONGTERM, %UBI_SHORTTERM,
+ * %UBI_UNKNOWN)
+ * @jhead: journal head the mutex belongs to (note, needed only to shut lockdep
+ * up by 'mutex_lock_nested()).
+ * @sync_callback: write-buffer synchronization callback
+ * @io_mutex: serializes write-buffer I/O
+ * @lock: serializes @buf, @lnum, @offs, @avail, @used, @next_ino and @inodes
+ * fields
+ * @timer: write-buffer timer
+ * @timeout: timer expire interval in jiffies
+ * @need_sync: it is set if its timer expired and needs sync
+ * @next_ino: points to the next position of the following inode number
+ * @inodes: stores the inode numbers of the nodes which are in wbuf
+ *
+ * The write-buffer synchronization callback is called when the write-buffer is
+ * synchronized in order to notify how much space was wasted due to
+ * write-buffer padding and how much free space is left in the LEB.
+ *
+ * Note: the fields @buf, @lnum, @offs, @avail and @used can be read under
+ * spin-lock or mutex because they are written under both mutex and spin-lock.
+ * @buf is appended to under mutex but overwritten under both mutex and
+ * spin-lock. Thus the data between @buf and @buf + @used can be read under
+ * spinlock.
+ */
+struct ubifs_wbuf {
+ struct ubifs_info *c;
+ void *buf;
+ int lnum;
+ int offs;
+ int avail;
+ int used;
+ int dtype;
+ int jhead;
+ int (*sync_callback)(struct ubifs_info *c, int lnum, int free, int pad);
+ struct mutex io_mutex;
+ spinlock_t lock;
+ int timeout;
+ int need_sync;
+ int next_ino;
+ ino_t *inodes;
+};
+
+/**
+ * struct ubifs_bud - bud logical eraseblock.
+ * @lnum: logical eraseblock number
+ * @start: where the (uncommitted) bud data starts
+ * @jhead: journal head number this bud belongs to
+ * @list: link in the list buds belonging to the same journal head
+ * @rb: link in the tree of all buds
+ */
+struct ubifs_bud {
+ int lnum;
+ int start;
+ int jhead;
+ struct list_head list;
+ struct rb_node rb;
+};
+
+/**
+ * struct ubifs_jhead - journal head.
+ * @wbuf: head's write-buffer
+ * @buds_list: list of bud LEBs belonging to this journal head
+ *
+ * Note, the @buds list is protected by the @c->buds_lock.
+ */
+struct ubifs_jhead {
+ struct ubifs_wbuf wbuf;
+ struct list_head buds_list;
+};
+
+/**
+ * struct ubifs_zbranch - key/coordinate/length branch stored in znodes.
+ * @key: key
+ * @znode: znode address in memory
+ * @lnum: LEB number of the target node (indexing node or data node)
+ * @offs: target node offset within @lnum
+ * @len: target node length
+ */
+struct ubifs_zbranch {
+ union ubifs_key key;
+ union {
+ struct ubifs_znode *znode;
+ void *leaf;
+ };
+ int lnum;
+ int offs;
+ int len;
+};
+
+/**
+ * struct ubifs_znode - in-memory representation of an indexing node.
+ * @parent: parent znode or NULL if it is the root
+ * @cnext: next znode to commit
+ * @flags: znode flags (%DIRTY_ZNODE, %COW_ZNODE or %OBSOLETE_ZNODE)
+ * @time: last access time (seconds)
+ * @level: level of the entry in the TNC tree
+ * @child_cnt: count of child znodes
+ * @iip: index in parent's zbranch array
+ * @alt: lower bound of key range has altered i.e. child inserted at slot 0
+ * @lnum: LEB number of the corresponding indexing node
+ * @offs: offset of the corresponding indexing node
+ * @len: length of the corresponding indexing node
+ * @zbranch: array of znode branches (@c->fanout elements)
+ */
+struct ubifs_znode {
+ struct ubifs_znode *parent;
+ struct ubifs_znode *cnext;
+ unsigned long flags;
+ unsigned long time;
+ int level;
+ int child_cnt;
+ int iip;
+ int alt;
+#ifdef CONFIG_UBIFS_FS_DEBUG
+ int lnum, offs, len;
+#endif
+ struct ubifs_zbranch zbranch[];
+};
+
+/**
+ * struct bu_info - bulk-read information.
+ * @key: first data node key
+ * @zbranch: zbranches of data nodes to bulk read
+ * @buf: buffer to read into
+ * @buf_len: buffer length
+ * @gc_seq: GC sequence number to detect races with GC
+ * @cnt: number of data nodes for bulk read
+ * @blk_cnt: number of data blocks including holes
+ * @oef: end of file reached
+ */
+struct bu_info {
+ union ubifs_key key;
+ struct ubifs_zbranch zbranch[UBIFS_MAX_BULK_READ];
+ void *buf;
+ int buf_len;
+ int gc_seq;
+ int cnt;
+ int blk_cnt;
+ int eof;
+};
+
+/**
+ * struct ubifs_node_range - node length range description data structure.
+ * @len: fixed node length
+ * @min_len: minimum possible node length
+ * @max_len: maximum possible node length
+ *
+ * If @max_len is %0, the node has fixed length @len.
+ */
+struct ubifs_node_range {
+ union {
+ int len;
+ int min_len;
+ };
+ int max_len;
+};
+
+/**
+ * struct ubifs_compressor - UBIFS compressor description structure.
+ * @compr_type: compressor type (%UBIFS_COMPR_LZO, etc)
+ * @cc: cryptoapi compressor handle
+ * @comp_mutex: mutex used during compression
+ * @decomp_mutex: mutex used during decompression
+ * @name: compressor name
+ * @capi_name: cryptoapi compressor name
+ */
+struct ubifs_compressor {
+ int compr_type;
+ char *name;
+ char *capi_name;
+ int (*decompress)(const unsigned char *in, size_t in_len,
+ unsigned char *out, size_t *out_len);
+};
+
+/**
+ * struct ubifs_budget_req - budget requirements of an operation.
+ *
+ * @fast: non-zero if the budgeting should try to acquire budget quickly and
+ * should not try to call write-back
+ * @recalculate: non-zero if @idx_growth, @data_growth, and @dd_growth fields
+ * have to be re-calculated
+ * @new_page: non-zero if the operation adds a new page
+ * @dirtied_page: non-zero if the operation makes a page dirty
+ * @new_dent: non-zero if the operation adds a new directory entry
+ * @mod_dent: non-zero if the operation removes or modifies an existing
+ * directory entry
+ * @new_ino: non-zero if the operation adds a new inode
+ * @new_ino_d: now much data newly created inode contains
+ * @dirtied_ino: how many inodes the operation makes dirty
+ * @dirtied_ino_d: now much data dirtied inode contains
+ * @idx_growth: how much the index will supposedly grow
+ * @data_growth: how much new data the operation will supposedly add
+ * @dd_growth: how much data that makes other data dirty the operation will
+ * supposedly add
+ *
+ * @idx_growth, @data_growth and @dd_growth are not used in budget request. The
+ * budgeting subsystem caches index and data growth values there to avoid
+ * re-calculating them when the budget is released. However, if @idx_growth is
+ * %-1, it is calculated by the release function using other fields.
+ *
+ * An inode may contain 4KiB of data at max., thus the widths of @new_ino_d
+ * is 13 bits, and @dirtied_ino_d - 15, because up to 4 inodes may be made
+ * dirty by the re-name operation.
+ *
+ * Note, UBIFS aligns node lengths to 8-bytes boundary, so the requester has to
+ * make sure the amount of inode data which contribute to @new_ino_d and
+ * @dirtied_ino_d fields are aligned.
+ */
+struct ubifs_budget_req {
+ unsigned int fast:1;
+ unsigned int recalculate:1;
+#ifndef UBIFS_DEBUG
+ unsigned int new_page:1;
+ unsigned int dirtied_page:1;
+ unsigned int new_dent:1;
+ unsigned int mod_dent:1;
+ unsigned int new_ino:1;
+ unsigned int new_ino_d:13;
+ unsigned int dirtied_ino:4;
+ unsigned int dirtied_ino_d:15;
+#else
+ /* Not bit-fields to check for overflows */
+ unsigned int new_page;
+ unsigned int dirtied_page;
+ unsigned int new_dent;
+ unsigned int mod_dent;
+ unsigned int new_ino;
+ unsigned int new_ino_d;
+ unsigned int dirtied_ino;
+ unsigned int dirtied_ino_d;
+#endif
+ int idx_growth;
+ int data_growth;
+ int dd_growth;
+};
+
+/**
+ * struct ubifs_orphan - stores the inode number of an orphan.
+ * @rb: rb-tree node of rb-tree of orphans sorted by inode number
+ * @list: list head of list of orphans in order added
+ * @new_list: list head of list of orphans added since the last commit
+ * @cnext: next orphan to commit
+ * @dnext: next orphan to delete
+ * @inum: inode number
+ * @new: %1 => added since the last commit, otherwise %0
+ */
+struct ubifs_orphan {
+ struct rb_node rb;
+ struct list_head list;
+ struct list_head new_list;
+ struct ubifs_orphan *cnext;
+ struct ubifs_orphan *dnext;
+ ino_t inum;
+ int new;
+};
+
+/**
+ * struct ubifs_mount_opts - UBIFS-specific mount options information.
+ * @unmount_mode: selected unmount mode (%0 default, %1 normal, %2 fast)
+ * @bulk_read: enable/disable bulk-reads (%0 default, %1 disabe, %2 enable)
+ * @chk_data_crc: enable/disable CRC data checking when reading data nodes
+ * (%0 default, %1 disabe, %2 enable)
+ * @override_compr: override default compressor (%0 - do not override and use
+ * superblock compressor, %1 - override and use compressor
+ * specified in @compr_type)
+ * @compr_type: compressor type to override the superblock compressor with
+ * (%UBIFS_COMPR_NONE, etc)
+ */
+struct ubifs_mount_opts {
+ unsigned int unmount_mode:2;
+ unsigned int bulk_read:2;
+ unsigned int chk_data_crc:2;
+ unsigned int override_compr:1;
+ unsigned int compr_type:2;
+};
+
+struct ubifs_debug_info;
+
+/**
+ * struct ubifs_info - UBIFS file-system description data structure
+ * (per-superblock).
+ * @vfs_sb: VFS @struct super_block object
+ * @bdi: backing device info object to make VFS happy and disable read-ahead
+ *
+ * @highest_inum: highest used inode number
+ * @max_sqnum: current global sequence number
+ * @cmt_no: commit number of the last successfully completed commit, protected
+ * by @commit_sem
+ * @cnt_lock: protects @highest_inum and @max_sqnum counters
+ * @fmt_version: UBIFS on-flash format version
+ * @uuid: UUID from super block
+ *
+ * @lhead_lnum: log head logical eraseblock number
+ * @lhead_offs: log head offset
+ * @ltail_lnum: log tail logical eraseblock number (offset is always 0)
+ * @log_mutex: protects the log, @lhead_lnum, @lhead_offs, @ltail_lnum, and
+ * @bud_bytes
+ * @min_log_bytes: minimum required number of bytes in the log
+ * @cmt_bud_bytes: used during commit to temporarily amount of bytes in
+ * committed buds
+ *
+ * @buds: tree of all buds indexed by bud LEB number
+ * @bud_bytes: how many bytes of flash is used by buds
+ * @buds_lock: protects the @buds tree, @bud_bytes, and per-journal head bud
+ * lists
+ * @jhead_cnt: count of journal heads
+ * @jheads: journal heads (head zero is base head)
+ * @max_bud_bytes: maximum number of bytes allowed in buds
+ * @bg_bud_bytes: number of bud bytes when background commit is initiated
+ * @old_buds: buds to be released after commit ends
+ * @max_bud_cnt: maximum number of buds
+ *
+ * @commit_sem: synchronizes committer with other processes
+ * @cmt_state: commit state
+ * @cs_lock: commit state lock
+ * @cmt_wq: wait queue to sleep on if the log is full and a commit is running
+ *
+ * @big_lpt: flag that LPT is too big to write whole during commit
+ * @no_chk_data_crc: do not check CRCs when reading data nodes (except during
+ * recovery)
+ * @bulk_read: enable bulk-reads
+ * @default_compr: default compression algorithm (%UBIFS_COMPR_LZO, etc)
+ *
+ * @tnc_mutex: protects the Tree Node Cache (TNC), @zroot, @cnext, @enext, and
+ * @calc_idx_sz
+ * @zroot: zbranch which points to the root index node and znode
+ * @cnext: next znode to commit
+ * @enext: next znode to commit to empty space
+ * @gap_lebs: array of LEBs used by the in-gaps commit method
+ * @cbuf: commit buffer
+ * @ileb_buf: buffer for commit in-the-gaps method
+ * @ileb_len: length of data in ileb_buf
+ * @ihead_lnum: LEB number of index head
+ * @ihead_offs: offset of index head
+ * @ilebs: pre-allocated index LEBs
+ * @ileb_cnt: number of pre-allocated index LEBs
+ * @ileb_nxt: next pre-allocated index LEBs
+ * @old_idx: tree of index nodes obsoleted since the last commit start
+ * @bottom_up_buf: a buffer which is used by 'dirty_cow_bottom_up()' in tnc.c
+ *
+ * @mst_node: master node
+ * @mst_offs: offset of valid master node
+ * @mst_mutex: protects the master node area, @mst_node, and @mst_offs
+ *
+ * @max_bu_buf_len: maximum bulk-read buffer length
+ * @bu_mutex: protects the pre-allocated bulk-read buffer and @c->bu
+ * @bu: pre-allocated bulk-read information
+ *
+ * @log_lebs: number of logical eraseblocks in the log
+ * @log_bytes: log size in bytes
+ * @log_last: last LEB of the log
+ * @lpt_lebs: number of LEBs used for lprops table
+ * @lpt_first: first LEB of the lprops table area
+ * @lpt_last: last LEB of the lprops table area
+ * @orph_lebs: number of LEBs used for the orphan area
+ * @orph_first: first LEB of the orphan area
+ * @orph_last: last LEB of the orphan area
+ * @main_lebs: count of LEBs in the main area
+ * @main_first: first LEB of the main area
+ * @main_bytes: main area size in bytes
+ *
+ * @key_hash_type: type of the key hash
+ * @key_hash: direntry key hash function
+ * @key_fmt: key format
+ * @key_len: key length
+ * @fanout: fanout of the index tree (number of links per indexing node)
+ *
+ * @min_io_size: minimal input/output unit size
+ * @min_io_shift: number of bits in @min_io_size minus one
+ * @leb_size: logical eraseblock size in bytes
+ * @half_leb_size: half LEB size
+ * @leb_cnt: count of logical eraseblocks
+ * @max_leb_cnt: maximum count of logical eraseblocks
+ * @old_leb_cnt: count of logical eraseblocks before re-size
+ * @ro_media: the underlying UBI volume is read-only
+ *
+ * @dirty_pg_cnt: number of dirty pages (not used)
+ * @dirty_zn_cnt: number of dirty znodes
+ * @clean_zn_cnt: number of clean znodes
+ *
+ * @budg_idx_growth: amount of bytes budgeted for index growth
+ * @budg_data_growth: amount of bytes budgeted for cached data
+ * @budg_dd_growth: amount of bytes budgeted for cached data that will make
+ * other data dirty
+ * @budg_uncommitted_idx: amount of bytes were budgeted for growth of the index,
+ * but which still have to be taken into account because
+ * the index has not been committed so far
+ * @space_lock: protects @budg_idx_growth, @budg_data_growth, @budg_dd_growth,
+ * @budg_uncommited_idx, @min_idx_lebs, @old_idx_sz, @lst,
+ * @nospace, and @nospace_rp;
+ * @min_idx_lebs: minimum number of LEBs required for the index
+ * @old_idx_sz: size of index on flash
+ * @calc_idx_sz: temporary variable which is used to calculate new index size
+ * (contains accurate new index size at end of TNC commit start)
+ * @lst: lprops statistics
+ * @nospace: non-zero if the file-system does not have flash space (used as
+ * optimization)
+ * @nospace_rp: the same as @nospace, but additionally means that even reserved
+ * pool is full
+ *
+ * @page_budget: budget for a page
+ * @inode_budget: budget for an inode
+ * @dent_budget: budget for a directory entry
+ *
+ * @ref_node_alsz: size of the LEB reference node aligned to the min. flash
+ * I/O unit
+ * @mst_node_alsz: master node aligned size
+ * @min_idx_node_sz: minimum indexing node aligned on 8-bytes boundary
+ * @max_idx_node_sz: maximum indexing node aligned on 8-bytes boundary
+ * @max_inode_sz: maximum possible inode size in bytes
+ * @max_znode_sz: size of znode in bytes
+ *
+ * @leb_overhead: how many bytes are wasted in an LEB when it is filled with
+ * data nodes of maximum size - used in free space reporting
+ * @dead_wm: LEB dead space watermark
+ * @dark_wm: LEB dark space watermark
+ * @block_cnt: count of 4KiB blocks on the FS
+ *
+ * @ranges: UBIFS node length ranges
+ * @ubi: UBI volume descriptor
+ * @di: UBI device information
+ * @vi: UBI volume information
+ *
+ * @orph_tree: rb-tree of orphan inode numbers
+ * @orph_list: list of orphan inode numbers in order added
+ * @orph_new: list of orphan inode numbers added since last commit
+ * @orph_cnext: next orphan to commit
+ * @orph_dnext: next orphan to delete
+ * @orphan_lock: lock for orph_tree and orph_new
+ * @orph_buf: buffer for orphan nodes
+ * @new_orphans: number of orphans since last commit
+ * @cmt_orphans: number of orphans being committed
+ * @tot_orphans: number of orphans in the rb_tree
+ * @max_orphans: maximum number of orphans allowed
+ * @ohead_lnum: orphan head LEB number
+ * @ohead_offs: orphan head offset
+ * @no_orphs: non-zero if there are no orphans
+ *
+ * @bgt: UBIFS background thread
+ * @bgt_name: background thread name
+ * @need_bgt: if background thread should run
+ * @need_wbuf_sync: if write-buffers have to be synchronized
+ *
+ * @gc_lnum: LEB number used for garbage collection
+ * @sbuf: a buffer of LEB size used by GC and replay for scanning
+ * @idx_gc: list of index LEBs that have been garbage collected
+ * @idx_gc_cnt: number of elements on the idx_gc list
+ * @gc_seq: incremented for every non-index LEB garbage collected
+ * @gced_lnum: last non-index LEB that was garbage collected
+ *
+ * @infos_list: links all 'ubifs_info' objects
+ * @umount_mutex: serializes shrinker and un-mount
+ * @shrinker_run_no: shrinker run number
+ *
+ * @space_bits: number of bits needed to record free or dirty space
+ * @lpt_lnum_bits: number of bits needed to record a LEB number in the LPT
+ * @lpt_offs_bits: number of bits needed to record an offset in the LPT
+ * @lpt_spc_bits: number of bits needed to space in the LPT
+ * @pcnt_bits: number of bits needed to record pnode or nnode number
+ * @lnum_bits: number of bits needed to record LEB number
+ * @nnode_sz: size of on-flash nnode
+ * @pnode_sz: size of on-flash pnode
+ * @ltab_sz: size of on-flash LPT lprops table
+ * @lsave_sz: size of on-flash LPT save table
+ * @pnode_cnt: number of pnodes
+ * @nnode_cnt: number of nnodes
+ * @lpt_hght: height of the LPT
+ * @pnodes_have: number of pnodes in memory
+ *
+ * @lp_mutex: protects lprops table and all the other lprops-related fields
+ * @lpt_lnum: LEB number of the root nnode of the LPT
+ * @lpt_offs: offset of the root nnode of the LPT
+ * @nhead_lnum: LEB number of LPT head
+ * @nhead_offs: offset of LPT head
+ * @lpt_drty_flgs: dirty flags for LPT special nodes e.g. ltab
+ * @dirty_nn_cnt: number of dirty nnodes
+ * @dirty_pn_cnt: number of dirty pnodes
+ * @check_lpt_free: flag that indicates LPT GC may be needed
+ * @lpt_sz: LPT size
+ * @lpt_nod_buf: buffer for an on-flash nnode or pnode
+ * @lpt_buf: buffer of LEB size used by LPT
+ * @nroot: address in memory of the root nnode of the LPT
+ * @lpt_cnext: next LPT node to commit
+ * @lpt_heap: array of heaps of categorized lprops
+ * @dirty_idx: a (reverse sorted) copy of the LPROPS_DIRTY_IDX heap as at
+ * previous commit start
+ * @uncat_list: list of un-categorized LEBs
+ * @empty_list: list of empty LEBs
+ * @freeable_list: list of freeable non-index LEBs (free + dirty == leb_size)
+ * @frdi_idx_list: list of freeable index LEBs (free + dirty == leb_size)
+ * @freeable_cnt: number of freeable LEBs in @freeable_list
+ *
+ * @ltab_lnum: LEB number of LPT's own lprops table
+ * @ltab_offs: offset of LPT's own lprops table
+ * @ltab: LPT's own lprops table
+ * @ltab_cmt: LPT's own lprops table (commit copy)
+ * @lsave_cnt: number of LEB numbers in LPT's save table
+ * @lsave_lnum: LEB number of LPT's save table
+ * @lsave_offs: offset of LPT's save table
+ * @lsave: LPT's save table
+ * @lscan_lnum: LEB number of last LPT scan
+ *
+ * @rp_size: size of the reserved pool in bytes
+ * @report_rp_size: size of the reserved pool reported to user-space
+ * @rp_uid: reserved pool user ID
+ * @rp_gid: reserved pool group ID
+ *
+ * @empty: if the UBI device is empty
+ * @replay_tree: temporary tree used during journal replay
+ * @replay_list: temporary list used during journal replay
+ * @replay_buds: list of buds to replay
+ * @cs_sqnum: sequence number of first node in the log (commit start node)
+ * @replay_sqnum: sequence number of node currently being replayed
+ * @need_recovery: file-system needs recovery
+ * @replaying: set to %1 during journal replay
+ * @unclean_leb_list: LEBs to recover when mounting ro to rw
+ * @rcvrd_mst_node: recovered master node to write when mounting ro to rw
+ * @size_tree: inode size information for recovery
+ * @remounting_rw: set while remounting from ro to rw (sb flags have MS_RDONLY)
+ * @always_chk_crc: always check CRCs (while mounting and remounting rw)
+ * @mount_opts: UBIFS-specific mount options
+ *
+ * @dbg: debugging-related information
+ */
+struct ubifs_info {
+ struct super_block *vfs_sb;
+
+ ino_t highest_inum;
+ unsigned long long max_sqnum;
+ unsigned long long cmt_no;
+ spinlock_t cnt_lock;
+ int fmt_version;
+ unsigned char uuid[16];
+
+ int lhead_lnum;
+ int lhead_offs;
+ int ltail_lnum;
+ struct mutex log_mutex;
+ int min_log_bytes;
+ long long cmt_bud_bytes;
+
+ struct rb_root buds;
+ long long bud_bytes;
+ spinlock_t buds_lock;
+ int jhead_cnt;
+ struct ubifs_jhead *jheads;
+ long long max_bud_bytes;
+ long long bg_bud_bytes;
+ struct list_head old_buds;
+ int max_bud_cnt;
+
+ struct rw_semaphore commit_sem;
+ int cmt_state;
+ spinlock_t cs_lock;
+ wait_queue_head_t cmt_wq;
+
+ unsigned int big_lpt:1;
+ unsigned int no_chk_data_crc:1;
+ unsigned int bulk_read:1;
+ unsigned int default_compr:2;
+
+ struct mutex tnc_mutex;
+ struct ubifs_zbranch zroot;
+ struct ubifs_znode *cnext;
+ struct ubifs_znode *enext;
+ int *gap_lebs;
+ void *cbuf;
+ void *ileb_buf;
+ int ileb_len;
+ int ihead_lnum;
+ int ihead_offs;
+ int *ilebs;
+ int ileb_cnt;
+ int ileb_nxt;
+ struct rb_root old_idx;
+ int *bottom_up_buf;
+
+ struct ubifs_mst_node *mst_node;
+ int mst_offs;
+ struct mutex mst_mutex;
+
+ int max_bu_buf_len;
+ struct mutex bu_mutex;
+ struct bu_info bu;
+
+ int log_lebs;
+ long long log_bytes;
+ int log_last;
+ int lpt_lebs;
+ int lpt_first;
+ int lpt_last;
+ int orph_lebs;
+ int orph_first;
+ int orph_last;
+ int main_lebs;
+ int main_first;
+ long long main_bytes;
+
+ uint8_t key_hash_type;
+ uint32_t (*key_hash)(const char *str, int len);
+ int key_fmt;
+ int key_len;
+ int fanout;
+
+ int min_io_size;
+ int min_io_shift;
+ int leb_size;
+ int half_leb_size;
+ int leb_cnt;
+ int max_leb_cnt;
+ int old_leb_cnt;
+ int ro_media;
+
+ long long budg_idx_growth;
+ long long budg_data_growth;
+ long long budg_dd_growth;
+ long long budg_uncommitted_idx;
+ spinlock_t space_lock;
+ int min_idx_lebs;
+ unsigned long long old_idx_sz;
+ unsigned long long calc_idx_sz;
+ struct ubifs_lp_stats lst;
+ unsigned int nospace:1;
+ unsigned int nospace_rp:1;
+
+ int page_budget;
+ int inode_budget;
+ int dent_budget;
+
+ int ref_node_alsz;
+ int mst_node_alsz;
+ int min_idx_node_sz;
+ int max_idx_node_sz;
+ long long max_inode_sz;
+ int max_znode_sz;
+
+ int leb_overhead;
+ int dead_wm;
+ int dark_wm;
+ int block_cnt;
+
+ struct ubifs_node_range ranges[UBIFS_NODE_TYPES_CNT];
+ struct ubi_volume_desc *ubi;
+ struct ubi_device_info di;
+ struct ubi_volume_info vi;
+
+ struct rb_root orph_tree;
+ struct list_head orph_list;
+ struct list_head orph_new;
+ struct ubifs_orphan *orph_cnext;
+ struct ubifs_orphan *orph_dnext;
+ spinlock_t orphan_lock;
+ void *orph_buf;
+ int new_orphans;
+ int cmt_orphans;
+ int tot_orphans;
+ int max_orphans;
+ int ohead_lnum;
+ int ohead_offs;
+ int no_orphs;
+
+ struct task_struct *bgt;
+ char bgt_name[sizeof(BGT_NAME_PATTERN) + 9];
+ int need_bgt;
+ int need_wbuf_sync;
+
+ int gc_lnum;
+ void *sbuf;
+ struct list_head idx_gc;
+ int idx_gc_cnt;
+ int gc_seq;
+ int gced_lnum;
+
+ struct list_head infos_list;
+ struct mutex umount_mutex;
+ unsigned int shrinker_run_no;
+
+ int space_bits;
+ int lpt_lnum_bits;
+ int lpt_offs_bits;
+ int lpt_spc_bits;
+ int pcnt_bits;
+ int lnum_bits;
+ int nnode_sz;
+ int pnode_sz;
+ int ltab_sz;
+ int lsave_sz;
+ int pnode_cnt;
+ int nnode_cnt;
+ int lpt_hght;
+ int pnodes_have;
+
+ struct mutex lp_mutex;
+ int lpt_lnum;
+ int lpt_offs;
+ int nhead_lnum;
+ int nhead_offs;
+ int lpt_drty_flgs;
+ int dirty_nn_cnt;
+ int dirty_pn_cnt;
+ int check_lpt_free;
+ long long lpt_sz;
+ void *lpt_nod_buf;
+ void *lpt_buf;
+ struct ubifs_nnode *nroot;
+ struct ubifs_cnode *lpt_cnext;
+ struct ubifs_lpt_heap lpt_heap[LPROPS_HEAP_CNT];
+ struct ubifs_lpt_heap dirty_idx;
+ struct list_head uncat_list;
+ struct list_head empty_list;
+ struct list_head freeable_list;
+ struct list_head frdi_idx_list;
+ int freeable_cnt;
+
+ int ltab_lnum;
+ int ltab_offs;
+ struct ubifs_lpt_lprops *ltab;
+ struct ubifs_lpt_lprops *ltab_cmt;
+ int lsave_cnt;
+ int lsave_lnum;
+ int lsave_offs;
+ int *lsave;
+ int lscan_lnum;
+
+ long long rp_size;
+ long long report_rp_size;
+ uid_t rp_uid;
+ gid_t rp_gid;
+
+ /* The below fields are used only during mounting and re-mounting */
+ int empty;
+ struct rb_root replay_tree;
+ struct list_head replay_list;
+ struct list_head replay_buds;
+ unsigned long long cs_sqnum;
+ unsigned long long replay_sqnum;
+ int need_recovery;
+ int replaying;
+ struct list_head unclean_leb_list;
+ struct ubifs_mst_node *rcvrd_mst_node;
+ struct rb_root size_tree;
+ int remounting_rw;
+ int always_chk_crc;
+ struct ubifs_mount_opts mount_opts;
+
+#ifdef CONFIG_UBIFS_FS_DEBUG
+ struct ubifs_debug_info *dbg;
+#endif
+};
+
+extern spinlock_t ubifs_infos_lock;
+extern struct kmem_cache *ubifs_inode_slab;
+extern const struct super_operations ubifs_super_operations;
+extern const struct address_space_operations ubifs_file_address_operations;
+extern const struct file_operations ubifs_file_operations;
+extern const struct inode_operations ubifs_file_inode_operations;
+extern const struct file_operations ubifs_dir_operations;
+extern const struct inode_operations ubifs_dir_inode_operations;
+extern const struct inode_operations ubifs_symlink_inode_operations;
+extern struct backing_dev_info ubifs_backing_dev_info;
+extern struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
+
+/* io.c */
+void ubifs_ro_mode(struct ubifs_info *c, int err);
+int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len);
+int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
+ int dtype);
+int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf);
+int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
+ int lnum, int offs);
+int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
+ int lnum, int offs);
+int ubifs_write_node(struct ubifs_info *c, void *node, int len, int lnum,
+ int offs, int dtype);
+int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
+ int offs, int quiet, int must_chk_crc);
+void ubifs_prepare_node(struct ubifs_info *c, void *buf, int len, int pad);
+void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last);
+int ubifs_io_init(struct ubifs_info *c);
+void ubifs_pad(const struct ubifs_info *c, void *buf, int pad);
+int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf);
+int ubifs_bg_wbufs_sync(struct ubifs_info *c);
+void ubifs_wbuf_add_ino_nolock(struct ubifs_wbuf *wbuf, ino_t inum);
+int ubifs_sync_wbufs_by_inode(struct ubifs_info *c, struct inode *inode);
+
+/* scan.c */
+struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
+ int offs, void *sbuf);
+void ubifs_scan_destroy(struct ubifs_scan_leb *sleb);
+int ubifs_scan_a_node(const struct ubifs_info *c, void *buf, int len, int lnum,
+ int offs, int quiet);
+struct ubifs_scan_leb *ubifs_start_scan(const struct ubifs_info *c, int lnum,
+ int offs, void *sbuf);
+void ubifs_end_scan(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
+ int lnum, int offs);
+int ubifs_add_snod(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
+ void *buf, int offs);
+void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs,
+ void *buf);
+
+/* log.c */
+void ubifs_add_bud(struct ubifs_info *c, struct ubifs_bud *bud);
+void ubifs_create_buds_lists(struct ubifs_info *c);
+int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs);
+struct ubifs_bud *ubifs_search_bud(struct ubifs_info *c, int lnum);
+struct ubifs_wbuf *ubifs_get_wbuf(struct ubifs_info *c, int lnum);
+int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum);
+int ubifs_log_end_commit(struct ubifs_info *c, int new_ltail_lnum);
+int ubifs_log_post_commit(struct ubifs_info *c, int old_ltail_lnum);
+int ubifs_consolidate_log(struct ubifs_info *c);
+
+/* journal.c */
+int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
+ const struct qstr *nm, const struct inode *inode,
+ int deletion, int xent);
+int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
+ const union ubifs_key *key, const void *buf, int len);
+int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode);
+int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode);
+int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
+ const struct dentry *old_dentry,
+ const struct inode *new_dir,
+ const struct dentry *new_dentry, int sync);
+int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
+ loff_t old_size, loff_t new_size);
+int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
+ const struct inode *inode, const struct qstr *nm);
+int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode1,
+ const struct inode *inode2);
+
+/* budget.c */
+int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req);
+void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req);
+void ubifs_release_dirty_inode_budget(struct ubifs_info *c,
+ struct ubifs_inode *ui);
+int ubifs_budget_inode_op(struct ubifs_info *c, struct inode *inode,
+ struct ubifs_budget_req *req);
+void ubifs_release_ino_dirty(struct ubifs_info *c, struct inode *inode,
+ struct ubifs_budget_req *req);
+void ubifs_cancel_ino_op(struct ubifs_info *c, struct inode *inode,
+ struct ubifs_budget_req *req);
+long long ubifs_get_free_space(struct ubifs_info *c);
+long long ubifs_get_free_space_nolock(struct ubifs_info *c);
+int ubifs_calc_min_idx_lebs(struct ubifs_info *c);
+void ubifs_convert_page_budget(struct ubifs_info *c);
+long long ubifs_reported_space(const struct ubifs_info *c, long long free);
+long long ubifs_calc_available(const struct ubifs_info *c, int min_idx_lebs);
+
+/* find.c */
+int ubifs_find_free_space(struct ubifs_info *c, int min_space, int *free,
+ int squeeze);
+int ubifs_find_free_leb_for_idx(struct ubifs_info *c);
+int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp,
+ int min_space, int pick_free);
+int ubifs_find_dirty_idx_leb(struct ubifs_info *c);
+int ubifs_save_dirty_idx_lnums(struct ubifs_info *c);
+
+/* tnc.c */
+int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
+ struct ubifs_znode **zn, int *n);
+int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
+ void *node, const struct qstr *nm);
+int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key,
+ void *node, int *lnum, int *offs);
+int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
+ int offs, int len);
+int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
+ int old_lnum, int old_offs, int lnum, int offs, int len);
+int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
+ int lnum, int offs, int len, const struct qstr *nm);
+int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key);
+int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
+ const struct qstr *nm);
+int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key,
+ union ubifs_key *to_key);
+int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum);
+struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
+ union ubifs_key *key,
+ const struct qstr *nm);
+void ubifs_tnc_close(struct ubifs_info *c);
+int ubifs_tnc_has_node(struct ubifs_info *c, union ubifs_key *key, int level,
+ int lnum, int offs, int is_idx);
+int ubifs_dirty_idx_node(struct ubifs_info *c, union ubifs_key *key, int level,
+ int lnum, int offs);
+/* Shared by tnc.c for tnc_commit.c */
+void destroy_old_idx(struct ubifs_info *c);
+int is_idx_node_in_tnc(struct ubifs_info *c, union ubifs_key *key, int level,
+ int lnum, int offs);
+int insert_old_idx_znode(struct ubifs_info *c, struct ubifs_znode *znode);
+int ubifs_tnc_get_bu_keys(struct ubifs_info *c, struct bu_info *bu);
+int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu);
+
+/* tnc_misc.c */
+struct ubifs_znode *ubifs_tnc_levelorder_next(struct ubifs_znode *zr,
+ struct ubifs_znode *znode);
+int ubifs_search_zbranch(const struct ubifs_info *c,
+ const struct ubifs_znode *znode,
+ const union ubifs_key *key, int *n);
+struct ubifs_znode *ubifs_tnc_postorder_first(struct ubifs_znode *znode);
+struct ubifs_znode *ubifs_tnc_postorder_next(struct ubifs_znode *znode);
+long ubifs_destroy_tnc_subtree(struct ubifs_znode *zr);
+struct ubifs_znode *ubifs_load_znode(struct ubifs_info *c,
+ struct ubifs_zbranch *zbr,
+ struct ubifs_znode *parent, int iip);
+int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+ void *node);
+
+/* tnc_commit.c */
+int ubifs_tnc_start_commit(struct ubifs_info *c, struct ubifs_zbranch *zroot);
+int ubifs_tnc_end_commit(struct ubifs_info *c);
+
+/* shrinker.c */
+int ubifs_shrinker(int nr_to_scan, gfp_t gfp_mask);
+
+/* commit.c */
+int ubifs_bg_thread(void *info);
+void ubifs_commit_required(struct ubifs_info *c);
+void ubifs_request_bg_commit(struct ubifs_info *c);
+int ubifs_run_commit(struct ubifs_info *c);
+void ubifs_recovery_commit(struct ubifs_info *c);
+int ubifs_gc_should_commit(struct ubifs_info *c);
+void ubifs_wait_for_commit(struct ubifs_info *c);
+
+/* master.c */
+int ubifs_read_master(struct ubifs_info *c);
+int ubifs_write_master(struct ubifs_info *c);
+
+/* sb.c */
+int ubifs_read_superblock(struct ubifs_info *c);
+struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c);
+int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup);
+
+/* replay.c */
+int ubifs_validate_entry(struct ubifs_info *c,
+ const struct ubifs_dent_node *dent);
+int ubifs_replay_journal(struct ubifs_info *c);
+
+/* gc.c */
+int ubifs_garbage_collect(struct ubifs_info *c, int anyway);
+int ubifs_gc_start_commit(struct ubifs_info *c);
+int ubifs_gc_end_commit(struct ubifs_info *c);
+void ubifs_destroy_idx_gc(struct ubifs_info *c);
+int ubifs_get_idx_gc_leb(struct ubifs_info *c);
+int ubifs_garbage_collect_leb(struct ubifs_info *c, struct ubifs_lprops *lp);
+
+/* orphan.c */
+int ubifs_add_orphan(struct ubifs_info *c, ino_t inum);
+void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum);
+int ubifs_orphan_start_commit(struct ubifs_info *c);
+int ubifs_orphan_end_commit(struct ubifs_info *c);
+int ubifs_mount_orphans(struct ubifs_info *c, int unclean, int read_only);
+int ubifs_clear_orphans(struct ubifs_info *c);
+
+/* lpt.c */
+int ubifs_calc_lpt_geom(struct ubifs_info *c);
+int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
+ int *lpt_lebs, int *big_lpt);
+int ubifs_lpt_init(struct ubifs_info *c, int rd, int wr);
+struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum);
+struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum);
+int ubifs_lpt_scan_nolock(struct ubifs_info *c, int start_lnum, int end_lnum,
+ ubifs_lpt_scan_callback scan_cb, void *data);
+
+/* Shared by lpt.c for lpt_commit.c */
+void ubifs_pack_lsave(struct ubifs_info *c, void *buf, int *lsave);
+void ubifs_pack_ltab(struct ubifs_info *c, void *buf,
+ struct ubifs_lpt_lprops *ltab);
+void ubifs_pack_pnode(struct ubifs_info *c, void *buf,
+ struct ubifs_pnode *pnode);
+void ubifs_pack_nnode(struct ubifs_info *c, void *buf,
+ struct ubifs_nnode *nnode);
+struct ubifs_pnode *ubifs_get_pnode(struct ubifs_info *c,
+ struct ubifs_nnode *parent, int iip);
+struct ubifs_nnode *ubifs_get_nnode(struct ubifs_info *c,
+ struct ubifs_nnode *parent, int iip);
+int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip);
+void ubifs_add_lpt_dirt(struct ubifs_info *c, int lnum, int dirty);
+void ubifs_add_nnode_dirt(struct ubifs_info *c, struct ubifs_nnode *nnode);
+uint32_t ubifs_unpack_bits(uint8_t **addr, int *pos, int nrbits);
+struct ubifs_nnode *ubifs_first_nnode(struct ubifs_info *c, int *hght);
+/* Needed only in debugging code in lpt_commit.c */
+int ubifs_unpack_nnode(const struct ubifs_info *c, void *buf,
+ struct ubifs_nnode *nnode);
+
+/* lpt_commit.c */
+int ubifs_lpt_start_commit(struct ubifs_info *c);
+int ubifs_lpt_end_commit(struct ubifs_info *c);
+int ubifs_lpt_post_commit(struct ubifs_info *c);
+void ubifs_lpt_free(struct ubifs_info *c, int wr_only);
+
+/* lprops.c */
+const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c,
+ const struct ubifs_lprops *lp,
+ int free, int dirty, int flags,
+ int idx_gc_cnt);
+void ubifs_get_lp_stats(struct ubifs_info *c, struct ubifs_lp_stats *lst);
+void ubifs_add_to_cat(struct ubifs_info *c, struct ubifs_lprops *lprops,
+ int cat);
+void ubifs_replace_cat(struct ubifs_info *c, struct ubifs_lprops *old_lprops,
+ struct ubifs_lprops *new_lprops);
+void ubifs_ensure_cat(struct ubifs_info *c, struct ubifs_lprops *lprops);
+int ubifs_categorize_lprops(const struct ubifs_info *c,
+ const struct ubifs_lprops *lprops);
+int ubifs_change_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
+ int flags_set, int flags_clean, int idx_gc_cnt);
+int ubifs_update_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
+ int flags_set, int flags_clean);
+int ubifs_read_one_lp(struct ubifs_info *c, int lnum, struct ubifs_lprops *lp);
+const struct ubifs_lprops *ubifs_fast_find_free(struct ubifs_info *c);
+const struct ubifs_lprops *ubifs_fast_find_empty(struct ubifs_info *c);
+const struct ubifs_lprops *ubifs_fast_find_freeable(struct ubifs_info *c);
+const struct ubifs_lprops *ubifs_fast_find_frdi_idx(struct ubifs_info *c);
+
+/* file.c */
+int ubifs_fsync(struct file *file, struct dentry *dentry, int datasync);
+int ubifs_setattr(struct dentry *dentry, struct iattr *attr);
+
+/* dir.c */
+struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
+ int mode);
+int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
+ struct kstat *stat);
+
+/* xattr.c */
+int ubifs_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags);
+ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf,
+ size_t size);
+ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size);
+int ubifs_removexattr(struct dentry *dentry, const char *name);
+
+/* super.c */
+struct inode *ubifs_iget(struct super_block *sb, unsigned long inum);
+int ubifs_iput(struct inode *inode);
+
+/* recovery.c */
+int ubifs_recover_master_node(struct ubifs_info *c);
+int ubifs_write_rcvrd_mst_node(struct ubifs_info *c);
+struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
+ int offs, void *sbuf, int grouped);
+struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
+ int offs, void *sbuf);
+int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf);
+int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf);
+int ubifs_rcvry_gc_commit(struct ubifs_info *c);
+int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key,
+ int deletion, loff_t new_size);
+int ubifs_recover_size(struct ubifs_info *c);
+void ubifs_destroy_size_tree(struct ubifs_info *c);
+
+/* ioctl.c */
+long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+void ubifs_set_inode_flags(struct inode *inode);
+#ifdef CONFIG_COMPAT
+long ubifs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+#endif
+
+/* compressor.c */
+int __init ubifs_compressors_init(void);
+void __exit ubifs_compressors_exit(void);
+void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int *out_len,
+ int *compr_type);
+int ubifs_decompress(const void *buf, int len, void *out, int *out_len,
+ int compr_type);
+
+#include "debug.h"
+#include "misc.h"
+#include "key.h"
+
+/* todo: Move these to a common U-Boot header */
+int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
+ unsigned char *out, size_t *out_len);
+int gunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp);
+
+#endif /* !__UBIFS_H__ */
diff --git a/include/asm-i386/ic/ali512x.h b/include/ali512x.h
index 5bc1bd7..5bc1bd7 100644
--- a/include/asm-i386/ic/ali512x.h
+++ b/include/ali512x.h
diff --git a/include/asm-arm/u-boot.h b/include/asm-arm/u-boot.h
index b11d555..cfd5a9b 100644
--- a/include/asm-arm/u-boot.h
+++ b/include/asm-arm/u-boot.h
@@ -39,7 +39,6 @@
typedef struct bd_info {
int bi_baudrate; /* serial console baudrate */
unsigned long bi_ip_addr; /* IP Address */
- unsigned char bi_enetaddr[6]; /* Ethernet adress */
struct environment_s *bi_env;
ulong bi_arch_number; /* unique id for this board */
ulong bi_boot_params; /* where this board expects params */
@@ -48,10 +47,6 @@ typedef struct bd_info {
ulong start;
ulong size;
} bi_dram[CONFIG_NR_DRAM_BANKS];
-#ifdef CONFIG_HAS_ETH1
- /* second onboard ethernet port */
- unsigned char bi_enet1addr[6];
-#endif
} bd_t;
#define bi_env_data bi_env->data
diff --git a/include/asm-avr32/u-boot.h b/include/asm-avr32/u-boot.h
index 85ef008..7e4001f 100644
--- a/include/asm-avr32/u-boot.h
+++ b/include/asm-avr32/u-boot.h
@@ -25,7 +25,6 @@
typedef struct bd_info {
unsigned long bi_baudrate;
unsigned long bi_ip_addr;
- unsigned char bi_enetaddr[6];
unsigned char bi_phy_id[4];
struct environment_s *bi_env;
unsigned long bi_board_number;
diff --git a/include/asm-blackfin/u-boot.h b/include/asm-blackfin/u-boot.h
index 9d2903b..a6e6cf0f 100644
--- a/include/asm-blackfin/u-boot.h
+++ b/include/asm-blackfin/u-boot.h
@@ -31,7 +31,6 @@
typedef struct bd_info {
int bi_baudrate; /* serial console baudrate */
unsigned long bi_ip_addr; /* IP Address */
- unsigned char bi_enetaddr[6]; /* Ethernet adress */
unsigned long bi_boot_params; /* where this board expects params */
unsigned long bi_memstart; /* start of DRAM memory */
phys_size_t bi_memsize; /* size of DRAM memory in bytes */
diff --git a/include/asm-i386/interrupt.h b/include/asm-i386/interrupt.h
index 315b400..7f408cb 100644
--- a/include/asm-i386/interrupt.h
+++ b/include/asm-i386/interrupt.h
@@ -1,7 +1,10 @@
/*
- * (C) Copyright 2008
+ * (C) Copyright 2009
* Graeme Russ, graeme.russ@gmail.com
*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se
+ *
* See file CREDITS for list of people who contributed to this
* project.
*
@@ -24,6 +27,47 @@
#ifndef __ASM_INTERRUPT_H_
#define __ASM_INTERRUPT_H_ 1
-void set_vector(int intnum, void *routine);
+/* cpu/i386/interrupts.c */
+void set_vector(u8 intnum, void *routine);
+
+/* lib_i386/interupts.c */
+void disable_irq(int irq);
+void enable_irq(int irq);
+
+/* Architecture specific functions */
+void mask_irq(int irq);
+void unmask_irq(int irq);
+void specific_eoi(int irq);
+
+extern char exception_stack[];
+
+#define __isr__ void __attribute__ ((regparm(0)))
+
+#define DECLARE_INTERRUPT(x) \
+ asm(".globl irq_"#x"\n" \
+ "irq_"#x":\n" \
+ "pusha \n" \
+ "pushl $"#x"\n" \
+ "pushl $irq_return\n" \
+ "jmp do_irq\n"); \
+ __isr__ irq_##x(void)
+
+#define DECLARE_EXCEPTION(x, f) \
+ asm(".globl exp_"#x"\n" \
+ "exp_"#x":\n" \
+ "pusha \n" \
+ "movl %esp, %ebx\n" \
+ "movl $exception_stack, %eax\n" \
+ "movl %eax, %esp \n" \
+ "pushl %ebx\n" \
+ "movl 32(%esp), %ebx\n" \
+ "xorl %edx, %edx\n" \
+ "movw 36(%esp), %dx\n" \
+ "pushl %edx\n" \
+ "pushl %ebx\n" \
+ "pushl $"#x"\n" \
+ "pushl $exp_return\n" \
+ "jmp "#f"\n"); \
+ __isr__ exp_##x(void)
#endif
diff --git a/include/asm-i386/u-boot-i386.h b/include/asm-i386/u-boot-i386.h
index 12d10a7..3921e01 100644
--- a/include/asm-i386/u-boot-i386.h
+++ b/include/asm-i386/u-boot-i386.h
@@ -43,8 +43,21 @@ extern ulong i386boot_bios_size; /* size of BIOS emulation code */
/* cpu/.../cpu.c */
int cpu_init(void);
+
+/* cpu/.../timer.c */
+void timer_isr(void *);
+typedef void (timer_fnc_t) (void);
+int register_timer_isr (timer_fnc_t *isr_func);
+
+/* Architecture specific - can be in cpu/i386/, lib_i386/, or $(BOARD)/ */
int timer_init(void);
+/* cpu/.../interrupts.c */
+int cpu_init_interrupts(void);
+
+/* cpu/.../exceptions.c */
+int cpu_init_exceptions(void);
+
/* board/.../... */
int board_init(void);
int dram_init(void);
diff --git a/include/asm-i386/u-boot.h b/include/asm-i386/u-boot.h
index fc5a2ae..9a1eec0 100644
--- a/include/asm-i386/u-boot.h
+++ b/include/asm-i386/u-boot.h
@@ -46,7 +46,6 @@ typedef struct bd_info {
unsigned long bi_sramsize; /* size of SRAM memory */
unsigned long bi_bootflags; /* boot / reboot flag (for LynxOS) */
unsigned long bi_ip_addr; /* IP Address */
- unsigned char bi_enetaddr[6]; /* Ethernet adress */
unsigned short bi_ethspeed; /* Ethernet speed in Mbps */
unsigned long bi_intfreq; /* Internal Freq, in MHz */
unsigned long bi_busfreq; /* Bus Freq, in MHz */
diff --git a/include/asm-m68k/u-boot.h b/include/asm-m68k/u-boot.h
index 5a0d5fe..a0f2983 100644
--- a/include/asm-m68k/u-boot.h
+++ b/include/asm-m68k/u-boot.h
@@ -48,7 +48,6 @@ typedef struct bd_info {
unsigned long bi_bootflags; /* boot / reboot flag (for LynxOS) */
unsigned long bi_boot_params; /* where this board expects params */
unsigned long bi_ip_addr; /* IP Address */
- unsigned char bi_enetaddr[6]; /* Ethernet adress */
unsigned short bi_ethspeed; /* Ethernet speed in Mbps */
unsigned long bi_intfreq; /* Internal Freq, in MHz */
unsigned long bi_busfreq; /* Bus Freq, in MHz */
@@ -61,18 +60,6 @@ typedef struct bd_info {
unsigned long bi_flbfreq; /* Flexbus Freq in MHz */
#endif
unsigned long bi_baudrate; /* Console Baudrate */
-
-#ifdef CONFIG_HAS_ETH1
- /* second onboard ethernet port */
- unsigned char bi_enet1addr[6];
-#endif
-#ifdef CONFIG_HAS_ETH2
- /* third onboard ethernet port */
- unsigned char bi_enet2addr[6];
-#endif
-#ifdef CONFIG_HAS_ETH3
- unsigned char bi_enet3addr[6];
-#endif
} bd_t;
#endif /* __ASSEMBLY__ */
diff --git a/include/asm-microblaze/u-boot.h b/include/asm-microblaze/u-boot.h
index 9db491e..543a6b1 100644
--- a/include/asm-microblaze/u-boot.h
+++ b/include/asm-microblaze/u-boot.h
@@ -41,7 +41,6 @@ typedef struct bd_info {
unsigned long bi_sramstart; /* start of SRAM memory */
unsigned long bi_sramsize; /* size of SRAM memory */
unsigned long bi_ip_addr; /* IP Address */
- unsigned char bi_enetaddr[6]; /* Ethernet adress */
unsigned long bi_baudrate; /* Console Baudrate */
} bd_t;
diff --git a/include/asm-mips/u-boot.h b/include/asm-mips/u-boot.h
index 9ecb9ac..d9c14ca 100644
--- a/include/asm-mips/u-boot.h
+++ b/include/asm-mips/u-boot.h
@@ -34,7 +34,6 @@
typedef struct bd_info {
int bi_baudrate; /* serial console baudrate */
unsigned long bi_ip_addr; /* IP Address */
- unsigned char bi_enetaddr[6]; /* Ethernet adress */
unsigned long bi_arch_number; /* unique id for this board */
unsigned long bi_boot_params; /* where this board expects params */
unsigned long bi_memstart; /* start of DRAM memory */
diff --git a/include/asm-nios/u-boot.h b/include/asm-nios/u-boot.h
index 3436185..bdb6cf2 100644
--- a/include/asm-nios/u-boot.h
+++ b/include/asm-nios/u-boot.h
@@ -41,7 +41,6 @@ typedef struct bd_info {
unsigned long bi_sramstart; /* start of SRAM memory */
unsigned long bi_sramsize; /* size of SRAM memory */
unsigned long bi_ip_addr; /* IP Address */
- unsigned char bi_enetaddr[6]; /* Ethernet adress */
unsigned long bi_baudrate; /* Console Baudrate */
} bd_t;
diff --git a/include/asm-nios2/u-boot.h b/include/asm-nios2/u-boot.h
index de8c405..ec844d0 100644
--- a/include/asm-nios2/u-boot.h
+++ b/include/asm-nios2/u-boot.h
@@ -40,7 +40,6 @@ typedef struct bd_info {
unsigned long bi_sramstart; /* start of SRAM memory */
unsigned long bi_sramsize; /* size of SRAM memory */
unsigned long bi_ip_addr; /* IP Address */
- unsigned char bi_enetaddr[6]; /* Ethernet adress */
unsigned long bi_baudrate; /* Console Baudrate */
} bd_t;
diff --git a/include/asm-ppc/u-boot.h b/include/asm-ppc/u-boot.h
index 7451905..e6c56e9 100644
--- a/include/asm-ppc/u-boot.h
+++ b/include/asm-ppc/u-boot.h
@@ -64,7 +64,7 @@ typedef struct bd_info {
#endif
unsigned long bi_bootflags; /* boot / reboot flag (for LynxOS) */
unsigned long bi_ip_addr; /* IP Address */
- unsigned char bi_enetaddr[6]; /* Ethernet adress */
+ unsigned char bi_enetaddr[6]; /* OLD: see README.enetaddr */
unsigned short bi_ethspeed; /* Ethernet speed in Mbps */
unsigned long bi_intfreq; /* Internal Freq, in MHz */
unsigned long bi_busfreq; /* Bus Freq, in MHz */
@@ -101,21 +101,19 @@ typedef struct bd_info {
#endif
#ifdef CONFIG_HAS_ETH1
- /* second onboard ethernet port */
- unsigned char bi_enet1addr[6];
+ unsigned char bi_enet1addr[6]; /* OLD: see README.enetaddr */
#endif
#ifdef CONFIG_HAS_ETH2
- /* third onboard ethernet port */
- unsigned char bi_enet2addr[6];
+ unsigned char bi_enet2addr[6]; /* OLD: see README.enetaddr */
#endif
#ifdef CONFIG_HAS_ETH3
- unsigned char bi_enet3addr[6];
+ unsigned char bi_enet3addr[6]; /* OLD: see README.enetaddr */
#endif
#ifdef CONFIG_HAS_ETH4
- unsigned char bi_enet4addr[6];
+ unsigned char bi_enet4addr[6]; /* OLD: see README.enetaddr */
#endif
#ifdef CONFIG_HAS_ETH5
- unsigned char bi_enet5addr[6];
+ unsigned char bi_enet5addr[6]; /* OLD: see README.enetaddr */
#endif
#if defined(CONFIG_405GP) || defined(CONFIG_405EP) || \
diff --git a/include/asm-ppc/unaligned.h b/include/asm-ppc/unaligned.h
new file mode 100644
index 0000000..5f1b1e3
--- /dev/null
+++ b/include/asm-ppc/unaligned.h
@@ -0,0 +1,16 @@
+#ifndef _ASM_POWERPC_UNALIGNED_H
+#define _ASM_POWERPC_UNALIGNED_H
+
+#ifdef __KERNEL__
+
+/*
+ * The PowerPC can do unaligned accesses itself in big endian mode.
+ */
+#include <linux/unaligned/access_ok.h>
+#include <linux/unaligned/generic.h>
+
+#define get_unaligned __get_unaligned_be
+#define put_unaligned __put_unaligned_be
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_UNALIGNED_H */
diff --git a/include/asm-sh/u-boot.h b/include/asm-sh/u-boot.h
index e89c193..27d43b9 100644
--- a/include/asm-sh/u-boot.h
+++ b/include/asm-sh/u-boot.h
@@ -34,7 +34,6 @@ typedef struct bd_info {
unsigned long bi_sramstart; /* start of SRAM memory */
unsigned long bi_sramsize; /* size of SRAM memory */
unsigned long bi_ip_addr; /* IP Address */
- unsigned char bi_enetaddr[6]; /* Ethernet adress */
unsigned long bi_baudrate; /* Console Baudrate */
unsigned long bi_boot_params; /* where this board expects params */
} bd_t;
diff --git a/include/asm-sparc/u-boot.h b/include/asm-sparc/u-boot.h
index c42e93c..209873f 100644
--- a/include/asm-sparc/u-boot.h
+++ b/include/asm-sparc/u-boot.h
@@ -52,22 +52,10 @@ typedef struct bd_info {
unsigned long bi_sramsize; /* size of SRAM memory */
unsigned long bi_bootflags; /* boot / reboot flag (for LynxOS) */
unsigned long bi_ip_addr; /* IP Address */
- unsigned char bi_enetaddr[6]; /* Ethernet adress */
unsigned short bi_ethspeed; /* Ethernet speed in Mbps */
unsigned long bi_intfreq; /* Internal Freq, in MHz */
unsigned long bi_busfreq; /* Bus Freq, in MHz */
unsigned long bi_baudrate; /* Console Baudrate */
-#ifdef CONFIG_HAS_ETH1
- /* second onboard ethernet port */
- unsigned char bi_enet1addr[6];
-#endif
-#ifdef CONFIG_HAS_ETH2
- /* third onboard ethernet port */
- unsigned char bi_enet2addr[6];
-#endif
-#ifdef CONFIG_HAS_ETH3
- unsigned char bi_enet3addr[6];
-#endif
} bd_t;
#endif /* __ASSEMBLY__ */
diff --git a/include/common.h b/include/common.h
index b75ea60..952ddff 100644
--- a/include/common.h
+++ b/include/common.h
@@ -352,13 +352,6 @@ void board_serial_init (void);
void board_ether_init (void);
#endif
-#if defined(CONFIG_RPXCLASSIC) || defined(CONFIG_MBX) || \
- defined(CONFIG_IAD210) || defined(CONFIG_XPEDITE1K) || \
- defined(CONFIG_METROBOX) || defined(CONFIG_KAREF) || \
- defined(CONFIG_V38B)
-void board_get_enetaddr (uchar *addr);
-#endif
-
#ifdef CONFIG_HERMES
/* $(BOARD)/hermes.c */
void hermes_start_lxt980 (int speed);
@@ -371,8 +364,6 @@ void display_mem_map(void);
void perform_soft_reset(void);
#endif
-void load_sernum_ethaddr (void);
-
/* $(BOARD)/$(BOARD).c */
int board_early_init_f (void);
int board_late_init (void);
diff --git a/include/config_cmd_all.h b/include/config_cmd_all.h
index 205dd1f..db1f55c 100644
--- a/include/config_cmd_all.h
+++ b/include/config_cmd_all.h
@@ -58,6 +58,7 @@
#define CONFIG_CMD_MII /* MII support */
#define CONFIG_CMD_MISC /* Misc functions like sleep etc*/
#define CONFIG_CMD_MMC /* MMC support */
+#define CONFIG_CMD_MTDPARTS /* mtd parts support */
#define CONFIG_CMD_NAND /* NAND support */
#define CONFIG_CMD_NET /* bootp, tftpboot, rarpboot */
#define CONFIG_CMD_NFS /* NFS support */
diff --git a/include/configs/ADNPESC1.h b/include/configs/ADNPESC1.h
index e61a3e1..0977bee 100644
--- a/include/configs/ADNPESC1.h
+++ b/include/configs/ADNPESC1.h
@@ -673,14 +673,14 @@
*
*/
/* No command line, one static partition */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
/* mtdparts command line support */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT ""
#define MTDPARTS_DEFAULT ""
*/
diff --git a/include/configs/Alaska8220.h b/include/configs/Alaska8220.h
index 2581fdf..576aa74 100644
--- a/include/configs/Alaska8220.h
+++ b/include/configs/Alaska8220.h
@@ -320,7 +320,7 @@
/* No command line, one static partition */
/*
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#define CONFIG_JFFS2_PART_SIZE 0x00400000
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
@@ -328,7 +328,7 @@
/* mtdparts command line support */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=alaska-0"
#define MTDPARTS_DEFAULT "mtdparts=alaska-0:4m(user)"
*/
diff --git a/include/configs/BAB7xx.h b/include/configs/BAB7xx.h
index 1910b34..40a1c40 100644
--- a/include/configs/BAB7xx.h
+++ b/include/configs/BAB7xx.h
@@ -219,7 +219,7 @@
*
*/
/* No command line, one static partition */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
@@ -229,7 +229,7 @@
* Note: fake mtd_id used, no linux mtd map file
*/
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=bab7xx-0"
#define MTDPARTS_DEFAULT "mtdparts=bab7xx-0:-(jffs2)"
*/
diff --git a/include/configs/BC3450.h b/include/configs/BC3450.h
index bced118..9934f29 100644
--- a/include/configs/BC3450.h
+++ b/include/configs/BC3450.h
@@ -346,7 +346,7 @@
#define CONFIG_SYS_FLASH_WRITE_TOUT 500 /* Flash Write Timeout (in ms) */
/* Dynamic MTD partition support */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=TQM5200-0"
#define MTDPARTS_DEFAULT "mtdparts=TQM5200-0:640k(firmware)," \
"1408k(kernel)," \
diff --git a/include/configs/CATcenter.h b/include/configs/CATcenter.h
index fa9fc23..39f41e6 100644
--- a/include/configs/CATcenter.h
+++ b/include/configs/CATcenter.h
@@ -781,7 +781,7 @@
*
*/
/* No command line, one static partition */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nand"
#define CONFIG_JFFS2_PART_SIZE 0x00200000
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
@@ -791,7 +791,7 @@
* Note: fake mtd_id used, no linux mtd map file
*/
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nand0=catcenter"
#define MTDPARTS_DEFAULT "mtdparts=catcenter:2m(nand)"
*/
diff --git a/include/configs/CPCI4052.h b/include/configs/CPCI4052.h
index 2677cfb..daa3c19 100644
--- a/include/configs/CPCI4052.h
+++ b/include/configs/CPCI4052.h
@@ -154,6 +154,12 @@
#define CONFIG_VERSION_VARIABLE 1 /* include version env variable */
+#define CONFIG_AUTOBOOT_KEYED 1
+#define CONFIG_AUTOBOOT_PROMPT \
+ "Press SPACE to abort autoboot in %d seconds\n", bootdelay
+#undef CONFIG_AUTOBOOT_DELAY_STR
+#define CONFIG_AUTOBOOT_STOP_STR " "
+
#define CONFIG_SYS_RX_ETH_BUFFER 16 /* use 16 rx buffer on 405 emac */
/*-----------------------------------------------------------------------
diff --git a/include/configs/CPCI405AB.h b/include/configs/CPCI405AB.h
index aae0d73..41795a7 100644
--- a/include/configs/CPCI405AB.h
+++ b/include/configs/CPCI405AB.h
@@ -151,6 +151,12 @@
#define CONFIG_VERSION_VARIABLE 1 /* include version env variable */
+#define CONFIG_AUTOBOOT_KEYED 1
+#define CONFIG_AUTOBOOT_PROMPT \
+ "Press SPACE to abort autoboot in %d seconds\n", bootdelay
+#undef CONFIG_AUTOBOOT_DELAY_STR
+#define CONFIG_AUTOBOOT_STOP_STR " "
+
#define CONFIG_SYS_RX_ETH_BUFFER 16 /* use 16 rx buffer on 405 emac */
/*-----------------------------------------------------------------------
diff --git a/include/configs/DASA_SIM.h b/include/configs/DASA_SIM.h
index 61704d0..21230e1 100644
--- a/include/configs/DASA_SIM.h
+++ b/include/configs/DASA_SIM.h
@@ -124,9 +124,9 @@
* Please note that CONFIG_SYS_SDRAM_BASE _must_ start at 0
*/
#define CONFIG_SYS_SDRAM_BASE 0x00000000
-#define CONFIG_SYS_FLASH_BASE 0xFFFD0000
+#define CONFIG_SYS_FLASH_BASE 0xFFFC0000
#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_FLASH_BASE
-#define CONFIG_SYS_MONITOR_LEN (192 << 10) /* Reserve 128 kB for Monitor */
+#define CONFIG_SYS_MONITOR_LEN (256 << 10) /* Reserve 128 kB for Monitor */
#define CONFIG_SYS_MALLOC_LEN (128 << 10) /* Reserve 128 kB for malloc() */
/*
diff --git a/include/configs/DB64360.h b/include/configs/DB64360.h
index daed934..160871b 100644
--- a/include/configs/DB64360.h
+++ b/include/configs/DB64360.h
@@ -230,7 +230,7 @@ ip=${ipaddr}:${serverip}${bootargs_end}; bootm 0x400000;\0"
*
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor1"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
@@ -242,7 +242,7 @@ ip=${ipaddr}:${serverip}${bootargs_end}; bootm 0x400000;\0"
* Note: fake mtd_id's used, no linux mtd map file.
*/
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor1=db64360-1"
#define MTDPARTS_DEFAULT "mtdparts=db64360-1:-(jffs2)"
*/
diff --git a/include/configs/DB64460.h b/include/configs/DB64460.h
index 604fd45..06fd157 100644
--- a/include/configs/DB64460.h
+++ b/include/configs/DB64460.h
@@ -168,7 +168,7 @@ ip=${ipaddr}:${serverip}${bootargs_end}; bootm 0x400000;\0"
*
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor1"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
@@ -180,7 +180,7 @@ ip=${ipaddr}:${serverip}${bootargs_end}; bootm 0x400000;\0"
* Note: fake mtd_id's used, no linux mtd map file.
*/
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor1=db64460-1"
#define MTDPARTS_DEFAULT "mtdparts=db64460-1:-(jffs2)"
*/
diff --git a/include/configs/DK1C20.h b/include/configs/DK1C20.h
index 6fdc566..db9c17d 100644
--- a/include/configs/DK1C20.h
+++ b/include/configs/DK1C20.h
@@ -539,14 +539,14 @@
*
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
/* mtdparts command line support */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT ""
#define MTDPARTS_DEFAULT ""
*/
diff --git a/include/configs/DK1S10.h b/include/configs/DK1S10.h
index 1d031f1..3bd270c 100644
--- a/include/configs/DK1S10.h
+++ b/include/configs/DK1S10.h
@@ -545,14 +545,14 @@
*
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
/* mtdparts command line support */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT ""
#define MTDPARTS_DEFAULT ""
*/
diff --git a/include/configs/DU405.h b/include/configs/DU405.h
index 1d20efe..d1edd24 100644
--- a/include/configs/DU405.h
+++ b/include/configs/DU405.h
@@ -32,8 +32,6 @@
* High Level Configuration Options
* (easy to change)
*/
-#define CONFIG_IDENT_STRING " $Name: $"
-
#define CONFIG_405GP 1 /* This is a PPC405 CPU */
#define CONFIG_4xx 1 /* ...member of PPC4xx family */
#define CONFIG_DU405 1 /* ...on a DU405 board */
@@ -49,8 +47,6 @@
#undef CONFIG_BOOTARGS
#define CONFIG_BOOTCOMMAND "bootm fff00000"
-#define CONFIG_PREBOOT /* enable preboot variable */
-
#define CONFIG_LOADS_ECHO 1 /* echo on for serial download */
#define CONFIG_SYS_LOADS_BAUD_CHANGE 1 /* allow baudrate change */
@@ -58,7 +54,9 @@
#define CONFIG_MII 1 /* MII PHY management */
#define CONFIG_PHY_ADDR 0 /* PHY address */
#define CONFIG_LXT971_NO_SLEEP 1 /* disable sleep mode in LXT971 */
-
+#define CONFIG_RESET_PHY_R 1 /* use reset_phy() to disable phy sleep mode */
+#define CONFIG_NET_MULTI 1
+#undef CONFIG_HAS_ETH1
/*
* BOOTP options
@@ -74,14 +72,13 @@
*/
#include <config_cmd_default.h>
-#define CONFIG_CMD_PCI
-#define CONFIG_CMD_IRQ
+#undef CONFIG_CMD_NFS
#define CONFIG_CMD_IDE
#define CONFIG_CMD_ELF
#define CONFIG_CMD_MII
#define CONFIG_CMD_DATE
#define CONFIG_CMD_EEPROM
-
+#define CONFIG_CMD_I2C
#define CONFIG_MAC_PARTITION
#define CONFIG_DOS_PARTITION
@@ -214,6 +211,7 @@
/*-----------------------------------------------------------------------
* I2C EEPROM (CAT24WC08) for environment
*/
+#define CONFIG_I2C_CMD_TREE 1
#define CONFIG_HARD_I2C /* I2c with hardware support */
#define CONFIG_SYS_I2C_SPEED 400000 /* I2C speed and slave address */
#define CONFIG_SYS_I2C_SLAVE 0x7F
diff --git a/include/configs/ELPPC.h b/include/configs/ELPPC.h
index 7939266..d2aa8b9 100644
--- a/include/configs/ELPPC.h
+++ b/include/configs/ELPPC.h
@@ -196,7 +196,7 @@
*
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
@@ -204,7 +204,7 @@
/* mtdparts command line support */
/* Note: fake mtd_id used, no linux mtd map file */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=elppc-0,nor1=elppc-1"
#define MTDPARTS_DEFAULT "mtdparts=elppc-0:-(jffs2),elppc-1:-(user)"
*/
diff --git a/include/configs/FPS850L.h b/include/configs/FPS850L.h
index 08408e2..f152230 100644
--- a/include/configs/FPS850L.h
+++ b/include/configs/FPS850L.h
@@ -216,7 +216,7 @@
/*-----------------------------------------------------------------------
* Dynamic MTD partition support
*/
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=TQM8xxL-0"
#define MTDPARTS_DEFAULT "mtdparts=TQM8xxL-0:256k(u-boot)," \
diff --git a/include/configs/FPS860L.h b/include/configs/FPS860L.h
index e5f3b60..5eaed84 100644
--- a/include/configs/FPS860L.h
+++ b/include/configs/FPS860L.h
@@ -216,7 +216,7 @@
/*-----------------------------------------------------------------------
* Dynamic MTD partition support
*/
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=TQM8xxL-0"
#define MTDPARTS_DEFAULT "mtdparts=TQM8xxL-0:256k(u-boot)," \
diff --git a/include/configs/HH405.h b/include/configs/HH405.h
index ed9a235..9233523 100644
--- a/include/configs/HH405.h
+++ b/include/configs/HH405.h
@@ -413,23 +413,6 @@
#define CONFIG_SYS_FPGA_BASE_ADDR 0xF0100100 /* FPGA internal Base Address */
-/* FPGA internal regs */
-#define CONFIG_SYS_FPGA_CTRL 0x000
-
-/* FPGA Control Reg */
-#define CONFIG_SYS_FPGA_CTRL_REV0 0x0001
-#define CONFIG_SYS_FPGA_CTRL_REV1 0x0002
-#define CONFIG_SYS_FPGA_CTRL_VGA0_BL 0x0004
-#define CONFIG_SYS_FPGA_CTRL_VGA0_BL_MODE 0x0008
-#define CONFIG_SYS_FPGA_CTRL_CF_RESET 0x0040
-#define CONFIG_SYS_FPGA_CTRL_PS2_PWR 0x0080
-#define CONFIG_SYS_FPGA_CTRL_CF_PWRN 0x0100 /* low active */
-#define CONFIG_SYS_FPGA_CTRL_CF_BUS_EN 0x0200
-#define CONFIG_SYS_FPGA_CTRL_LCD_CLK 0x7000 /* Mask for lcd clock */
-#define CONFIG_SYS_FPGA_CTRL_OW_ENABLE 0x8000
-
-#define CONFIG_SYS_FPGA_STATUS_CF_DETECT 0x8000
-
#define LCD_CLK_OFF 0x0000 /* Off */
#define LCD_CLK_02083 0x1000 /* 2.083 MHz */
#define LCD_CLK_03135 0x2000 /* 3.135 MHz */
diff --git a/include/configs/IAD210.h b/include/configs/IAD210.h
index ca488c6..ea1e706 100644
--- a/include/configs/IAD210.h
+++ b/include/configs/IAD210.h
@@ -67,6 +67,7 @@
/* using this define saves us updating another source file */
#define CONFIG_BOARD_EARLY_INIT_F 1
+#define CONFIG_MISC_INIT_R
#undef CONFIG_BOOTARGS
/* #define CONFIG_BOOTCOMMAND \
diff --git a/include/configs/LANTEC.h b/include/configs/LANTEC.h
index f14d945..6e8a4b8 100644
--- a/include/configs/LANTEC.h
+++ b/include/configs/LANTEC.h
@@ -352,14 +352,14 @@
*
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
/* mtdparts command line support */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT ""
#define MTDPARTS_DEFAULT ""
*/
diff --git a/include/configs/MBX860T.h b/include/configs/MBX860T.h
index 4cb3a69..0c28710 100644
--- a/include/configs/MBX860T.h
+++ b/include/configs/MBX860T.h
@@ -50,6 +50,8 @@
#undef CONFIG_8xx_TFTP_MODE
#endif
+#define CONFIG_MISC_INIT_R
+
#define CONFIG_DRAM_SPEED (CONFIG_8xx_BUSCLOCK) /* MHz */
#define CONFIG_BOOTCOMMAND "bootm FE020000" /* autoboot command */
#define CONFIG_BOOTARGS " "
diff --git a/include/configs/MHPC.h b/include/configs/MHPC.h
index 8e7f9cd..19a288c 100644
--- a/include/configs/MHPC.h
+++ b/include/configs/MHPC.h
@@ -200,7 +200,7 @@
*
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
@@ -208,7 +208,7 @@
/* mtdparts command line support */
/* Note: fake mtd_id used, no linux mtd map file */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=mhpc-0"
#define MTDPARTS_DEFAULT "mtdparts=mhpc-0:-(jffs2)"
*/
diff --git a/include/configs/MIP405.h b/include/configs/MIP405.h
index c58ce05..a3869c8 100644
--- a/include/configs/MIP405.h
+++ b/include/configs/MIP405.h
@@ -243,7 +243,7 @@
*
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
@@ -251,7 +251,7 @@
/* mtdparts command line support */
/* Note: fake mtd_id used, no linux mtd map file */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=mip405-0"
#define MTDPARTS_DEFAULT "mtdparts=mip405-0:-(jffs2)"
*/
diff --git a/include/configs/ML2.h b/include/configs/ML2.h
index 1902397..5fcc173 100644
--- a/include/configs/ML2.h
+++ b/include/configs/ML2.h
@@ -249,7 +249,7 @@
*
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00080000
@@ -257,7 +257,7 @@
/* mtdparts command line support */
/* Note: fake mtd_id used, no linux mtd map file */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=ml2-0"
#define MTDPARTS_DEFAULT "mtdparts=ml2-0:-@512k(jffs2)"
*/
diff --git a/include/configs/MPC8266ADS.h b/include/configs/MPC8266ADS.h
index fe1cc17..4fd86d3 100644
--- a/include/configs/MPC8266ADS.h
+++ b/include/configs/MPC8266ADS.h
@@ -563,14 +563,14 @@
*
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
/* mtdparts command line support */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT ""
#define MTDPARTS_DEFAULT ""
*/
diff --git a/include/configs/NC650.h b/include/configs/NC650.h
index 0b97f0c..6343cfe 100644
--- a/include/configs/NC650.h
+++ b/include/configs/NC650.h
@@ -440,13 +440,13 @@
*/
/* No command line, one static partition */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nand0"
#define CONFIG_JFFS2_PART_SIZE 0x00400000
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
/* mtdparts command line support */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=nc650-0,nand0=nc650-nand"
#define MTDPARTS_DEFAULT "mtdparts=nc650-0:1m(kernel1),1m(kernel2)," \
diff --git a/include/configs/NETTA.h b/include/configs/NETTA.h
index 34fdba5..724e807 100644
--- a/include/configs/NETTA.h
+++ b/include/configs/NETTA.h
@@ -702,7 +702,7 @@
*
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nand0"
#define CONFIG_JFFS2_PART_SIZE 0x00100000
#define CONFIG_JFFS2_PART_OFFSET 0x00200000
@@ -710,7 +710,7 @@
/* mtdparts command line support */
/* Note: fake mtd_id used, no linux mtd map file */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nand0=netta-nand"
#define MTDPARTS_DEFAULT "mtdparts=netta-nand:1m@2m(jffs2)"
*/
diff --git a/include/configs/PPChameleonEVB.h b/include/configs/PPChameleonEVB.h
index d2eae1d..16baf8c 100644
--- a/include/configs/PPChameleonEVB.h
+++ b/include/configs/PPChameleonEVB.h
@@ -804,14 +804,14 @@
*/
/* No command line, one static partition */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nand0"
#define CONFIG_JFFS2_PART_SIZE 0x00400000
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
/* mtdparts command line support */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=PPChameleon-0,nand0=ppchameleonevb-nand"
*/
diff --git a/include/configs/R360MPI.h b/include/configs/R360MPI.h
index bab4460..830f4bc 100644
--- a/include/configs/R360MPI.h
+++ b/include/configs/R360MPI.h
@@ -167,14 +167,14 @@
*/
/* No command line, one static partition
* use all the space starting at offset 3MB*/
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00300000
/* mtdparts command line support */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=r360-0"
#define MTDPARTS_DEFAULT "mtdparts=r360-0:-@3m(user)"
*/
diff --git a/include/configs/RBC823.h b/include/configs/RBC823.h
index 280175a..f36244d 100644
--- a/include/configs/RBC823.h
+++ b/include/configs/RBC823.h
@@ -429,7 +429,7 @@
*
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
@@ -437,7 +437,7 @@
/* mtdparts command line support */
/* Note: fake mtd_id used, no linux mtd map file */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT ""
#define MTDPARTS_DEFAULT ""
*/
diff --git a/include/configs/RPXClassic.h b/include/configs/RPXClassic.h
index 162ef09..bec5278 100644
--- a/include/configs/RPXClassic.h
+++ b/include/configs/RPXClassic.h
@@ -53,6 +53,7 @@
#define CONFIG_SYS_DISCOVER_PHY 1
#define CONFIG_MII 1
#endif /* CONFIG_FEC_ENET */
+#define CONFIG_MISC_INIT_R
/* Video console (graphic: Epson SED13806 on ECCX board, no keyboard */
#if 1
diff --git a/include/configs/Rattler.h b/include/configs/Rattler.h
index 01d0d5f..5b6f271 100644
--- a/include/configs/Rattler.h
+++ b/include/configs/Rattler.h
@@ -202,7 +202,7 @@
*
*/
/* No command line, one static partition */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00100000
@@ -210,7 +210,7 @@
/* mtdparts command line support */
/* Note: fake mtd_id used, no linux mtd map file */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=rattler-0"
#define MTDPARTS_DEFAULT "mtdparts=rattler-0:-@1m(jffs2)"
*/
diff --git a/include/configs/SIMPC8313.h b/include/configs/SIMPC8313.h
index b939cfa..e20527e 100644
--- a/include/configs/SIMPC8313.h
+++ b/include/configs/SIMPC8313.h
@@ -189,7 +189,7 @@
#define CONFIG_JFFS2_DEV "nand0"
/* mtdparts command line support */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nand0=nand0"
#define MTDPARTS_DEFAULT "mtdparts=nand0:2M(u-boot),6M(kernel),-(jffs2)"
diff --git a/include/configs/SXNI855T.h b/include/configs/SXNI855T.h
index 9857bf6..cac04b4 100644
--- a/include/configs/SXNI855T.h
+++ b/include/configs/SXNI855T.h
@@ -174,7 +174,7 @@
*
*/
/* No command line, one static partition */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
/*
#define CONFIG_JFFS2_DEV "nor0"
@@ -189,7 +189,7 @@
/* mtdparts command line support */
/* Note: fake mtd_id used, no linux mtd map file */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=sixnet-0,nand0=sixnet-nand"
#define MTDPARTS_DEFAULT "mtdparts=sixnet-0:7680k@512k();sixnet-nand:2m(jffs2-nand)"
*/
diff --git a/include/configs/TB5200.h b/include/configs/TB5200.h
index b42d3d9..92b4fa5 100644
--- a/include/configs/TB5200.h
+++ b/include/configs/TB5200.h
@@ -275,7 +275,7 @@
(= chip selects) */
/* Dynamic MTD partition support */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=TQM5200-0"
#if defined(CONFIG_TQM5200_B)
#define MTDPARTS_DEFAULT "mtdparts=TQM5200-0:768k(firmware)," \
diff --git a/include/configs/TQM5200.h b/include/configs/TQM5200.h
index 6850eba..d374981 100644
--- a/include/configs/TQM5200.h
+++ b/include/configs/TQM5200.h
@@ -407,7 +407,7 @@
#endif
/* Dynamic MTD partition support */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=TQM5200-0"
#ifdef CONFIG_STK52XX
diff --git a/include/configs/TQM823L.h b/include/configs/TQM823L.h
index 8934d51..87e5a65 100644
--- a/include/configs/TQM823L.h
+++ b/include/configs/TQM823L.h
@@ -231,7 +231,7 @@
/*-----------------------------------------------------------------------
* Dynamic MTD partition support
*/
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=TQM8xxL-0"
#define MTDPARTS_DEFAULT "mtdparts=TQM8xxL-0:256k(u-boot)," \
diff --git a/include/configs/TQM823M.h b/include/configs/TQM823M.h
index fd41573..f666443 100644
--- a/include/configs/TQM823M.h
+++ b/include/configs/TQM823M.h
@@ -227,7 +227,7 @@
/*-----------------------------------------------------------------------
* Dynamic MTD partition support
*/
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=TQM8xxM-0"
#define MTDPARTS_DEFAULT "mtdparts=TQM8xxM-0:512k(u-boot)," \
diff --git a/include/configs/TQM834x.h b/include/configs/TQM834x.h
index e126dc3..b74b404 100644
--- a/include/configs/TQM834x.h
+++ b/include/configs/TQM834x.h
@@ -537,7 +537,7 @@ extern int tqm834x_num_flash_banks;
* JFFS2 partitions
*/
/* mtdparts command line support */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=TQM834x-0"
/* default mtd partition table */
diff --git a/include/configs/TQM850L.h b/include/configs/TQM850L.h
index 77eb5a9..dc80b47 100644
--- a/include/configs/TQM850L.h
+++ b/include/configs/TQM850L.h
@@ -216,7 +216,7 @@
/*-----------------------------------------------------------------------
* Dynamic MTD partition support
*/
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=TQM8xxL-0"
#define MTDPARTS_DEFAULT "mtdparts=TQM8xxL-0:256k(u-boot)," \
diff --git a/include/configs/TQM850M.h b/include/configs/TQM850M.h
index bb8825b..2289443 100644
--- a/include/configs/TQM850M.h
+++ b/include/configs/TQM850M.h
@@ -216,7 +216,7 @@
/*-----------------------------------------------------------------------
* Dynamic MTD partition support
*/
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=TQM8xxM-0"
#define MTDPARTS_DEFAULT "mtdparts=TQM8xxM-0:512k(u-boot)," \
diff --git a/include/configs/TQM855L.h b/include/configs/TQM855L.h
index 2ccbaf8..999bdaa 100644
--- a/include/configs/TQM855L.h
+++ b/include/configs/TQM855L.h
@@ -221,7 +221,7 @@
/*-----------------------------------------------------------------------
* Dynamic MTD partition support
*/
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=TQM8xxL-0"
#define MTDPARTS_DEFAULT "mtdparts=TQM8xxL-0:256k(u-boot)," \
diff --git a/include/configs/TQM855M.h b/include/configs/TQM855M.h
index 8a65183..b54967d 100644
--- a/include/configs/TQM855M.h
+++ b/include/configs/TQM855M.h
@@ -256,7 +256,7 @@
/*-----------------------------------------------------------------------
* Dynamic MTD partition support
*/
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=TQM8xxM-0"
#define MTDPARTS_DEFAULT "mtdparts=TQM8xxM-0:512k(u-boot)," \
diff --git a/include/configs/TQM85xx.h b/include/configs/TQM85xx.h
index 3b2272c..72db26c 100644
--- a/include/configs/TQM85xx.h
+++ b/include/configs/TQM85xx.h
@@ -597,14 +597,14 @@
#define CONFIG_JFFS2_NAND 1
-#ifdef CONFIG_JFFS2_CMDLINE
+#ifdef CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nand0=TQM85xx-nand"
#define MTDPARTS_DEFAULT "mtdparts=TQM85xx-nand:-"
#else
#define CONFIG_JFFS2_DEV "nand0" /* NAND device jffs2 lives on */
#define CONFIG_JFFS2_PART_OFFSET 0 /* start of jffs2 partition */
#define CONFIG_JFFS2_PART_SIZE 0x200000 /* size of jffs2 partition */
-#endif /* CONFIG_JFFS2_CMDLINE */
+#endif /* CONFIG_CMD_MTDPARTS */
#endif /* CONFIG_NAND */
diff --git a/include/configs/TQM860L.h b/include/configs/TQM860L.h
index 8bd1fe0..2e2a165 100644
--- a/include/configs/TQM860L.h
+++ b/include/configs/TQM860L.h
@@ -220,7 +220,7 @@
/*-----------------------------------------------------------------------
* Dynamic MTD partition support
*/
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=TQM8xxL-0"
#define MTDPARTS_DEFAULT "mtdparts=TQM8xxL-0:256k(u-boot)," \
diff --git a/include/configs/TQM860M.h b/include/configs/TQM860M.h
index ad2c71c..1148f2e 100644
--- a/include/configs/TQM860M.h
+++ b/include/configs/TQM860M.h
@@ -221,7 +221,7 @@
/*-----------------------------------------------------------------------
* Dynamic MTD partition support
*/
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=TQM8xxM-0"
#define MTDPARTS_DEFAULT "mtdparts=TQM8xxM-0:512k(u-boot)," \
diff --git a/include/configs/TQM862L.h b/include/configs/TQM862L.h
index 0a5180e..577f982 100644
--- a/include/configs/TQM862L.h
+++ b/include/configs/TQM862L.h
@@ -224,7 +224,7 @@
/*-----------------------------------------------------------------------
* Dynamic MTD partition support
*/
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=TQM8xxL-0"
#define MTDPARTS_DEFAULT "mtdparts=TQM8xxL-0:256k(u-boot)," \
diff --git a/include/configs/TQM862M.h b/include/configs/TQM862M.h
index ee6980c..69070e6 100644
--- a/include/configs/TQM862M.h
+++ b/include/configs/TQM862M.h
@@ -225,7 +225,7 @@
/*-----------------------------------------------------------------------
* Dynamic MTD partition support
*/
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=TQM8xxM-0"
#define MTDPARTS_DEFAULT "mtdparts=TQM8xxM-0:512k(u-boot)," \
diff --git a/include/configs/TQM866M.h b/include/configs/TQM866M.h
index 421a2d8..bb68614 100644
--- a/include/configs/TQM866M.h
+++ b/include/configs/TQM866M.h
@@ -265,7 +265,7 @@
/*-----------------------------------------------------------------------
* Dynamic MTD partition support
*/
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=TQM8xxM-0"
#define MTDPARTS_DEFAULT "mtdparts=TQM8xxM-0:512k(u-boot)," \
diff --git a/include/configs/XPEDITE1K.h b/include/configs/XPEDITE1K.h
index 8d44ec6..74e55c9 100644
--- a/include/configs/XPEDITE1K.h
+++ b/include/configs/XPEDITE1K.h
@@ -38,6 +38,7 @@
#define CONFIG_440 1
#define CONFIG_440GX 1 /* 440 GX */
#define CONFIG_BOARD_EARLY_INIT_F 1 /* Call board_pre_init */
+#define CONFIG_MISC_INIT_R
#undef CONFIG_SYS_DRAM_TEST /* Disable-takes long time! */
#define CONFIG_SYS_CLK_FREQ 33333333 /* external freq to pll */
diff --git a/include/configs/ZUMA.h b/include/configs/ZUMA.h
index 08c4ced..b73aaa8 100644
--- a/include/configs/ZUMA.h
+++ b/include/configs/ZUMA.h
@@ -130,7 +130,7 @@
*
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
@@ -138,7 +138,7 @@
/* mtdparts command line support */
/* Note: fake mtd_id used, no linux mtd map file */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor1=zuma-1,nor2=zuma-2"
#define MTDPARTS_DEFAULT "mtdparts=zuma-1:-(jffs2),zuma-2:-(user)"
*/
diff --git a/include/configs/apollon.h b/include/configs/apollon.h
index dff47fc..f83dd9c 100644
--- a/include/configs/apollon.h
+++ b/include/configs/apollon.h
@@ -258,7 +258,7 @@
#define CONFIG_ENV_ADDR 0x00020000
#ifdef CONFIG_SYS_USE_UBI
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "onenand0=onenand"
#define MTDPARTS_DEFAULT "mtdparts=onenand:128k(bootloader)," \
"128k(params)," \
diff --git a/include/configs/cm5200.h b/include/configs/cm5200.h
index ddcc6aa..54cf40d 100644
--- a/include/configs/cm5200.h
+++ b/include/configs/cm5200.h
@@ -222,7 +222,7 @@
/*
* MTD configuration
*/
-#define CONFIG_JFFS2_CMDLINE 1
+#define CONFIG_CMD_MTDPARTS 1
#define MTDIDS_DEFAULT "nor0=cm5200-0"
#define MTDPARTS_DEFAULT "mtdparts=cm5200-0:" \
"384k(uboot),128k(env)," \
diff --git a/include/configs/cmc_pu2.h b/include/configs/cmc_pu2.h
index d9acb47..e5c74e1 100644
--- a/include/configs/cmc_pu2.h
+++ b/include/configs/cmc_pu2.h
@@ -143,6 +143,7 @@
#endif
+#define CONFIG_MISC_INIT_R
#define CONFIG_SYS_LONGHELP
#define AT91_SMART_MEDIA_ALE (1 << 22) /* our ALE is AD22 */
diff --git a/include/configs/debris.h b/include/configs/debris.h
index 4d65f6a..dc59df9 100644
--- a/include/configs/debris.h
+++ b/include/configs/debris.h
@@ -234,7 +234,7 @@
*
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
@@ -246,7 +246,7 @@
* Note: fake mtd_id's used, no linux mtd map file.
*/
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=debris-0"
#define MTDPARTS_DEFAULT "mtdparts=debris-0:-(jffs2)"
*/
diff --git a/include/configs/digsy_mtc.h b/include/configs/digsy_mtc.h
new file mode 100644
index 0000000..2716d5b
--- /dev/null
+++ b/include/configs/digsy_mtc.h
@@ -0,0 +1,346 @@
+/*
+ * (C) Copyright 2003-2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2005-2007
+ * Modified for InterControl digsyMTC MPC5200 board by
+ * Frank Bodammer, GCD Hard- & Software GmbH,
+ * frank.bodammer@gcd-solutions.de
+ *
+ * (C) Copyright 2009 Semihalf
+ * Optimized for digsyMTC by: Grzegorz Bernacki <gjb@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program\; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+/*
+ * High Level Configuration Options
+ */
+
+#define CONFIG_MPC5xxx 1 /* This is an MPC5xxx CPU */
+#define CONFIG_MPC5200 1 /* (more precisely an MPC5200 CPU) */
+#define CONFIG_DIGSY_MTC 1 /* ... on InterControl digsyMTC board */
+
+#define CONFIG_SYS_MPC5XXX_CLKIN 33000000
+
+#define BOOTFLAG_COLD 0x01
+#define BOOTFLAG_WARM 0x02
+
+#define CONFIG_SYS_CACHELINE_SIZE 32
+
+/*
+ * Serial console configuration
+ */
+#define CONFIG_PSC_CONSOLE 4 /* console is on PSC4 */
+#define CONFIG_BAUDRATE 115200 /* ... at 115200 bps */
+#define CONFIG_SYS_BAUDRATE_TABLE \
+ { 9600, 19200, 38400, 57600, 115200, 230400 }
+
+/*
+ * PCI Mapping:
+ * 0x40000000 - 0x4fffffff - PCI Memory
+ * 0x50000000 - 0x50ffffff - PCI IO Space
+ */
+#define CONFIG_PCI 1
+#define CONFIG_PCI_PNP 1
+#define CONFIG_PCI_SCAN_SHOW 1
+
+#define CONFIG_PCI_MEM_BUS 0x40000000
+#define CONFIG_PCI_MEM_PHYS CONFIG_PCI_MEM_BUS
+#define CONFIG_PCI_MEM_SIZE 0x10000000
+
+#define CONFIG_PCI_IO_BUS 0x50000000
+#define CONFIG_PCI_IO_PHYS CONFIG_PCI_IO_BUS
+#define CONFIG_PCI_IO_SIZE 0x01000000
+
+/*
+ * Partitions
+ */
+#define CONFIG_DOS_PARTITION
+#define CONFIG_BZIP2
+
+/*
+ * Command line configuration.
+ */
+#include <config_cmd_default.h>
+
+#define CONFIG_CMD_DFL
+#define CONFIG_CMD_CACHE
+#define CONFIG_CMD_DATE
+#define CONFIG_CMD_DHCP
+#define CONFIG_CMD_DIAG
+#define CONFIG_CMD_EEPROM
+#define CONFIG_CMD_ELF
+#define CONFIG_CMD_EXT2
+#define CONFIG_CMD_FAT
+#define CONFIG_CMD_I2C
+#define CONFIG_CMD_IDE
+#define CONFIG_CMD_IRQ
+#define CONFIG_CMD_MII
+#define CONFIG_CMD_PCI
+#define CONFIG_CMD_PING
+#define CONFIG_CMD_REGINFO
+#define CONFIG_CMD_SAVES
+#define CONFIG_CMD_USB
+
+#if (TEXT_BASE == 0xFF000000)
+#define CONFIG_SYS_LOWBOOT 1
+#endif
+
+/*
+ * Autobooting
+ */
+#define CONFIG_BOOTDELAY 1
+
+#undef CONFIG_BOOTARGS
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+ "netdev=eth0\0" \
+ "console=ttyPSC0\0" \
+ "kernel_addr_r=400000\0" \
+ "fdt_addr_r=600000\0" \
+ "nfsargs=setenv bootargs root=/dev/nfs rw " \
+ "nfsroot=${serverip}:${rootpath}\0" \
+ "addip=setenv bootargs ${bootargs} " \
+ "ip=${ipaddr}:${serverip}:${gatewayip}:"\
+ "${netmask}:${hostname}:${netdev}:off panic=1\0" \
+ "addcons=setenv bootargs ${bootargs} console=${console},${baudrate}\0"\
+ "rootpath=/opt/eldk/ppc_6xx\0" \
+ "net_nfs=tftp ${kernel_addr_r} ${bootfile};" \
+ "tftp ${fdt_addr_r} ${fdt_file};" \
+ "run nfsargs addip addcons;" \
+ "bootm ${kernel_addr_r} - ${fdt_addr_r}\0" \
+ "load=tftp 200000 ${u-boot}\0" \
+ "update=protect off FFF00000 +${filesize};" \
+ "erase FFF00000 +${filesize};" \
+ "cp.b 200000 FFF00000 ${filesize};" \
+ "protect on FFF00000 +${filesize}\0" \
+ ""
+
+/*
+ * I2C configuration
+ */
+#define CONFIG_HARD_I2C 1
+#define CONFIG_SYS_I2C_MODULE 1
+#define CONFIG_SYS_I2C_SPEED 100000
+#define CONFIG_SYS_I2C_SLAVE 0x7F
+
+/*
+ * EEPROM configuration
+ */
+#define CONFIG_SYS_I2C_EEPROM_ADDR 0x50 /* 1010000x */
+#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 1
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 3
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 70
+
+/*
+ * RTC configuration
+ */
+#define CONFIG_RTC_DS1337
+#define CONFIG_SYS_I2C_RTC_ADDR 0x68
+
+/*
+ * Flash configuration
+ */
+#define CONFIG_SYS_FLASH_CFI 1
+#define CONFIG_FLASH_CFI_DRIVER 1
+
+#define CONFIG_SYS_FLASH_BASE 0xFF000000
+#define CONFIG_SYS_FLASH_SIZE 0x01000000
+
+#define CONFIG_SYS_MAX_FLASH_BANKS 1
+#define CONFIG_SYS_MAX_FLASH_SECT 256
+#define CONFIG_FLASH_16BIT
+#define CONFIG_SYS_FLASH_CFI_WIDTH FLASH_CFI_16BIT
+#define CONFIG_SYS_FLASH_BANKS_LIST { CONFIG_SYS_FLASH_BASE }
+#define CONFIG_SYS_FLASH_ERASE_TOUT 240000
+#define CONFIG_SYS_FLASH_WRITE_TOUT 500
+
+#define CONFIG_OF_LIBFDT 1
+#define CONFIG_OF_BOARD_SETUP 1
+
+#define OF_CPU "PowerPC,5200@0"
+#define OF_SOC "soc5200@f0000000"
+#define OF_TBCLK (bd->bi_busfreq / 4)
+
+#define CONFIG_BOARD_EARLY_INIT_R
+#define CONFIG_MISC_INIT_R
+
+/*
+ * Environment settings
+ */
+#define CONFIG_ENV_IS_IN_FLASH 1
+#if defined(CONFIG_LOWBOOT)
+#define CONFIG_ENV_ADDR 0xFF060000
+#else /* CONFIG_LOWBOOT */
+#define CONFIG_ENV_ADDR 0xFFF60000
+#endif /* CONFIG_LOWBOOT */
+#define CONFIG_ENV_SIZE 0x10000
+#define CONFIG_ENV_SECT_SIZE 0x20000
+#define CONFIG_ENV_OVERWRITE 1
+
+/*
+ * Memory map
+ */
+#define CONFIG_SYS_MBAR 0xF0000000
+#define CONFIG_SYS_SDRAM_BASE 0x00000000
+#if !defined(CONFIG_SYS_LOWBOOT)
+#define CONFIG_SYS_DEFAULT_MBAR 0x80000000
+#else
+#define CONFIG_SYS_DEFAULT_MBAR 0xF0000000
+#endif
+
+/*
+ * Use SRAM until RAM will be available
+ */
+#define CONFIG_SYS_INIT_RAM_ADDR MPC5XXX_SRAM
+#define CONFIG_SYS_INIT_RAM_END MPC5XXX_SRAM_SIZE
+
+#define CONFIG_SYS_GBL_DATA_SIZE 4096
+#define CONFIG_SYS_GBL_DATA_OFFSET \
+ (CONFIG_SYS_INIT_RAM_END - CONFIG_SYS_GBL_DATA_SIZE)
+#define CONFIG_SYS_INIT_SP_OFFSET CONFIG_SYS_GBL_DATA_OFFSET
+
+#define CONFIG_SYS_MONITOR_BASE TEXT_BASE
+#if (CONFIG_SYS_MONITOR_BASE < CONFIG_SYS_FLASH_BASE)
+#define CONFIG_SYS_RAMBOOT 1
+#endif
+
+#define CONFIG_SYS_MONITOR_LEN (256 << 10)
+#define CONFIG_SYS_MALLOC_LEN (4096 << 10)
+#define CONFIG_SYS_BOOTMAPSZ (8 << 20)
+
+/*
+ * Ethernet configuration
+ */
+#define CONFIG_MPC5xxx_FEC 1
+#define CONFIG_MPC5xxx_FEC_MII100
+#define CONFIG_PHY_ADDR 0x00
+#define CONFIG_PHY_RESET_DELAY 1000
+
+#define CONFIG_NETCONSOLE /* include NetConsole support */
+
+/*
+ * GPIO configuration
+ */
+#define CONFIG_SYS_GPS_PORT_CONFIG 0xA2552112
+
+/*
+ * Miscellaneous configurable options
+ */
+#define CONFIG_SYS_LONGHELP
+#define CONFIG_AUTO_COMPLETE 1
+#define CONFIG_SYS_PROMPT "=> "
+#define CONFIG_SYS_HUSH_PARSER
+#define CONFIG_SYS_PROMPT_HUSH_PS2 "> "
+
+#define CONFIG_AUTOBOOT_KEYED
+#define CONFIG_AUTOBOOT_PROMPT "autoboot in %d seconds\n", bootdelay
+#define CONFIG_AUTOBOOT_DELAY_STR " "
+
+#define CONFIG_LOOPW 1
+#define CONFIG_MX_CYCLIC 1
+#define CONFIG_ZERO_BOOTDELAY_CHECK
+
+#define CONFIG_SYS_CBSIZE 1024
+#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE+sizeof(CONFIG_SYS_PROMPT)+16)
+#define CONFIG_SYS_MAXARGS 32
+#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE
+
+#define CONFIG_SYS_ALT_MEMTEST
+#define CONFIG_SYS_MEMTEST_SCRATCH 0x00001000
+#define CONFIG_SYS_MEMTEST_START 0x00010000
+#define CONFIG_SYS_MEMTEST_END 0x019fffff
+
+#define CONFIG_SYS_LOAD_ADDR 0x00100000
+
+#define CONFIG_SYS_HZ 1000
+
+/*
+ * Various low-level settings
+ */
+#define CONFIG_SYS_SDRAM_CS1 1
+#define CONFIG_SYS_XLB_PIPELINING 1
+
+#define CONFIG_SYS_HID0_INIT HID0_ICE | HID0_ICFI
+#define CONFIG_SYS_HID0_FINAL HID0_ICE
+
+#if defined(CONFIG_SYS_LOWBOOT)
+#define CONFIG_SYS_BOOTCS_START CONFIG_SYS_FLASH_BASE
+#define CONFIG_SYS_BOOTCS_SIZE CONFIG_SYS_FLASH_SIZE
+#define CONFIG_SYS_BOOTCS_CFG 0x0002DD00
+#endif
+
+#define CONFIG_SYS_CS4_START 0x60000000
+#define CONFIG_SYS_CS4_SIZE 0x1000
+#define CONFIG_SYS_CS4_CFG 0x0008FC00
+
+#define CONFIG_SYS_CS0_START CONFIG_SYS_FLASH_BASE
+#define CONFIG_SYS_CS0_SIZE CONFIG_SYS_FLASH_SIZE
+#define CONFIG_SYS_CS0_CFG 0x0002DD00
+
+#define CONFIG_SYS_CS_BURST 0x00000000
+#define CONFIG_SYS_CS_DEADCYCLE 0x11111111
+
+#if !defined(CONFIG_SYS_LOWBOOT)
+#define CONFIG_SYS_RESET_ADDRESS 0xfff00100
+#else
+#define CONFIG_SYS_RESET_ADDRESS 0xff000100
+#endif
+
+/*
+ * USB
+ */
+#define CONFIG_USB_OHCI_NEW
+#define CONFIG_SYS_OHCI_BE_CONTROLLER
+#define CONFIG_USB_STORAGE
+
+#define CONFIG_USB_CLOCK 0x00013333
+#define CONFIG_USB_CONFIG 0x00002000
+
+#define CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS 15
+#define CONFIG_SYS_USB_OHCI_REGS_BASE MPC5XXX_USB
+#define CONFIG_SYS_USB_OHCI_SLOT_NAME "mpc5200"
+#define CONFIG_SYS_USB_OHCI_CPU_INIT
+
+/*
+ * IDE/ATA
+ */
+#define CONFIG_IDE_RESET
+#define CONFIG_IDE_PREINIT
+
+#define CONFIG_SYS_ATA_CS_ON_I2C2
+#define CONFIG_SYS_IDE_MAXBUS 1
+#define CONFIG_SYS_IDE_MAXDEVICE 1
+
+#define CONFIG_SYS_ATA_IDE0_OFFSET 0x0000
+#define CONFIG_SYS_ATA_BASE_ADDR MPC5XXX_ATA
+#define CONFIG_SYS_ATA_DATA_OFFSET (0x0060)
+#define CONFIG_SYS_ATA_REG_OFFSET (CONFIG_SYS_ATA_DATA_OFFSET)
+#define CONFIG_SYS_ATA_ALT_OFFSET (0x005C)
+#define CONFIG_SYS_ATA_STRIDE 4
+
+#define CONFIG_ATAPI 1
+#define CONFIG_LBA48 1
+
+#endif /* __CONFIG_H */
+
diff --git a/include/configs/eNET.h b/include/configs/eNET.h
index 447c7bc..84e1aef 100644
--- a/include/configs/eNET.h
+++ b/include/configs/eNET.h
@@ -40,8 +40,8 @@
#define DEBUG_PARSER
#define CONFIG_X86 1 /* Intel X86 CPU */
-#define CONFIG_SC520 1 /* AMD SC520 */
-#define CONFIG_SC520_SSI
+#define CONFIG_SYS_SC520 1 /* AMD SC520 */
+#define CONFIG_SYS_SC520_SSI
#define CONFIG_SHOW_BOOT_PROGRESS 1
#define CONFIG_LAST_STAGE_INIT 1
@@ -90,7 +90,7 @@
#define CONFIG_CMD_RUN /* run command in env variable */
#define CONFIG_CMD_SETGETDCR /* DCR support on 4xx */
#define CONFIG_CMD_XIMG /* Load part of Multi Image */
-#undef CONFIG_CMD_IRQ /* IRQ Information */
+#define CONFIG_CMD_IRQ /* IRQ Information */
#define CONFIG_BOOTDELAY 15
#define CONFIG_BOOTARGS "root=/dev/mtdblock0 console=ttyS0,9600"
@@ -142,12 +142,14 @@
* CPU Features
*/
#define CONFIG_SYS_SC520_HIGH_SPEED 0 /* 100 or 133MHz */
-#undef CONFIG_SYS_RESET_SC520 /* use SC520 MMCR's to reset cpu */
-#define CONFIG_SYS_TIMER_SC520 /* use SC520 swtimers */
-#undef CONFIG_SYS_TIMER_GENERIC /* use the i8254 PIT timers */
-#undef CONFIG_SYS_TIMER_TSC /* use the Pentium TSC timers */
+#undef CONFIG_SYS_SC520_RESET /* use SC520 MMCR's to reset cpu */
+#define CONFIG_SYS_SC520_TIMER /* use SC520 swtimers */
+#undef CONFIG_SYS_GENERIC_TIMER /* use the i8254 PIT timers */
+#undef CONFIG_SYS_TSC_TIMER /* use the Pentium TSC timers */
#define CONFIG_SYS_USE_SIO_UART 0 /* prefer the uarts on the SIO to those
* in the SC520 on the CDP */
+#define CONFIG_SYS_PCAT_INTERRUPTS
+#define CONFIG_SYS_NUM_IRQS 16
/*-----------------------------------------------------------------------
* Memory organization
diff --git a/include/configs/ep7312.h b/include/configs/ep7312.h
index 0581842..322a3ca 100644
--- a/include/configs/ep7312.h
+++ b/include/configs/ep7312.h
@@ -158,7 +158,7 @@
*
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
@@ -166,7 +166,7 @@
/* mtdparts command line support */
/* Note: fake mtd_id used, no linux mtd map file */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=ep7312-0"
#define MTDPARTS_DEFAULT "mtdparts=ep7312-0:-(jffs2)"
*/
diff --git a/include/configs/ep8260.h b/include/configs/ep8260.h
index d49d02f..3f4425a 100644
--- a/include/configs/ep8260.h
+++ b/include/configs/ep8260.h
@@ -758,7 +758,7 @@
*
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
@@ -766,7 +766,7 @@
/* mtdparts command line support */
/* Note: fake mtd_id used, no linux mtd map file */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT ""
#define MTDPARTS_DEFAULT ""
*/
diff --git a/include/configs/fx12mm.h b/include/configs/fx12mm.h
index 5844567..27c6e7d 100644
--- a/include/configs/fx12mm.h
+++ b/include/configs/fx12mm.h
@@ -37,7 +37,7 @@
/* cmd config */
#define CONFIG_CMD_JFFS2
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#undef CONFIG_CMD_NET
/* sdram */
diff --git a/include/configs/hymod.h b/include/configs/hymod.h
index 0fdcda2..2dacfb6 100644
--- a/include/configs/hymod.h
+++ b/include/configs/hymod.h
@@ -730,14 +730,14 @@
*
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
/* mtdparts command line support */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT ""
#define MTDPARTS_DEFAULT ""
*/
diff --git a/include/configs/idmr.h b/include/configs/idmr.h
index 1dd89f9..944d06f 100644
--- a/include/configs/idmr.h
+++ b/include/configs/idmr.h
@@ -229,7 +229,7 @@
/* Dynamic MTD partition support */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=idmr-0"
#define MTDPARTS_DEFAULT "mtdparts=idmr-0:128k(u-boot)," \
diff --git a/include/configs/impa7.h b/include/configs/impa7.h
index bb3c02e..a3d023f 100644
--- a/include/configs/impa7.h
+++ b/include/configs/impa7.h
@@ -160,14 +160,14 @@
*
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00020000
/* mtdparts command line support */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=impA7 NOR Flash Bank #0,nor1=impA7 NOR Flash Bank #1"
#define MTDPARTS_DEFAULT "mtdparts=impA7 NOR Flash Bank #0:-(FileSystem1);impA7 NOR Flash Bank #1:-(FileSystem2)"
*/
diff --git a/include/configs/imx31_litekit.h b/include/configs/imx31_litekit.h
index 6c150ae..9ac6eec 100644
--- a/include/configs/imx31_litekit.h
+++ b/include/configs/imx31_litekit.h
@@ -170,7 +170,7 @@
/*
* JFFS2 partitions
*/
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#endif /* __CONFIG_H */
diff --git a/include/configs/imx31_phycore.h b/include/configs/imx31_phycore.h
index 2dd9e92..cbc0b92 100644
--- a/include/configs/imx31_phycore.h
+++ b/include/configs/imx31_phycore.h
@@ -175,7 +175,7 @@
/*
* JFFS2 partitions
*/
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
/* EET platform additions */
diff --git a/include/configs/incaip.h b/include/configs/incaip.h
index a18ba80..2129dfd 100644
--- a/include/configs/incaip.h
+++ b/include/configs/incaip.h
@@ -168,14 +168,14 @@
* JFFS2 partitions
*/
/* No command line, one static partition, use all space on the device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor1"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
/* mtdparts command line support */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=INCA-IP Bank 0"
#define MTDPARTS_DEFAULT "mtdparts=INCA-IP Bank 0:192k(uboot)," \
"64k(env)," \
diff --git a/include/configs/innokom.h b/include/configs/innokom.h
index d9b1555..043ae2f 100644
--- a/include/configs/innokom.h
+++ b/include/configs/innokom.h
@@ -203,7 +203,7 @@
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
@@ -211,7 +211,7 @@
/* mtdparts command line support */
/* Note: fake mtd_id used, no linux mtd map file */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=innokom-0"
*/
diff --git a/include/configs/microblaze-generic.h b/include/configs/microblaze-generic.h
index ac18c87..aa117c8 100644
--- a/include/configs/microblaze-generic.h
+++ b/include/configs/microblaze-generic.h
@@ -259,7 +259,7 @@
#if defined(CONFIG_CMD_JFFS2)
/* JFFS2 partitions */
-#define CONFIG_JFFS2_CMDLINE /* mtdparts command line support */
+#define CONFIG_CMD_MTDPARTS /* mtdparts command line support */
#define MTDIDS_DEFAULT "nor0=ml401-0"
/* default mtd partition table */
diff --git a/include/configs/modnet50.h b/include/configs/modnet50.h
index c4f5286..27213a8 100644
--- a/include/configs/modnet50.h
+++ b/include/configs/modnet50.h
@@ -182,7 +182,7 @@
*
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00080000
@@ -190,7 +190,7 @@
/* mtdparts command line support */
/* Note: fake mtd_id used, no linux mtd map file */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=modnet50-0"
#define MTDPARTS_DEFAULT "mtdparts=modnet50-0:-@512k(jffs2)"
*/
diff --git a/include/configs/motionpro.h b/include/configs/motionpro.h
index e6e3729..99a02cc 100644
--- a/include/configs/motionpro.h
+++ b/include/configs/motionpro.h
@@ -275,7 +275,7 @@
/*
* MTD configuration
*/
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=motionpro-0"
#define MTDPARTS_DEFAULT "mtdparts=motionpro-0:" \
"13m(fs),2m(kernel),256k(uboot)," \
diff --git a/include/configs/mx1fs2.h b/include/configs/mx1fs2.h
index aaa4e98..a19eb78 100644
--- a/include/configs/mx1fs2.h
+++ b/include/configs/mx1fs2.h
@@ -176,7 +176,7 @@
*/
/* No command line, one static partition, whole device */
/*
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00050000
@@ -184,7 +184,7 @@
/* mtdparts command line support */
/* Note: fake mtd_id used, no linux mtd map file */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=mx1fs2-0"
#ifdef BUS32BIT_VERSION
diff --git a/include/configs/mx31ads.h b/include/configs/mx31ads.h
index 1649f1f..c31c06a 100644
--- a/include/configs/mx31ads.h
+++ b/include/configs/mx31ads.h
@@ -194,7 +194,7 @@
/*
* JFFS2 partitions
*/
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#endif /* __CONFIG_H */
diff --git a/include/configs/netstar.h b/include/configs/netstar.h
index 3b22e48..0b38549 100644
--- a/include/configs/netstar.h
+++ b/include/configs/netstar.h
@@ -121,7 +121,7 @@
/*
* partitions (mtdparts command line support)
*/
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=omapflash.0,nand0=omapnand.0"
#define MTDPARTS_DEFAULT "mtdparts=" \
"omapflash.0:8k@16k(env),8k(r_env),448k@576k(u-boot);" \
diff --git a/include/configs/omap2420h4.h b/include/configs/omap2420h4.h
index 92df0b4..983b5f2 100644
--- a/include/configs/omap2420h4.h
+++ b/include/configs/omap2420h4.h
@@ -296,7 +296,7 @@
* JFFS2 partitions
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor1"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
@@ -304,7 +304,7 @@
/* mtdparts command line support */
/* Note: fake mtd_id used, no linux mtd map file */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor1=omap2420-1"
#define MTDPARTS_DEFAULT "mtdparts=omap2420-1:-(jffs2)"
*/
diff --git a/include/configs/qong.h b/include/configs/qong.h
index ccc2625..a67006a 100644
--- a/include/configs/qong.h
+++ b/include/configs/qong.h
@@ -212,7 +212,7 @@
/*
* JFFS2 partitions
*/
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=physmap-flash.0"
#define MTDPARTS_DEFAULT \
"mtdparts=physmap-flash.0:256k(U-Boot),128k(env1)," \
diff --git a/include/configs/sc3.h b/include/configs/sc3.h
index 515b097..5b68ef9 100644
--- a/include/configs/sc3.h
+++ b/include/configs/sc3.h
@@ -430,7 +430,7 @@ extern unsigned long offsetOfEnvironment;
#define CONFIG_JFFS2_NAND 1 /* jffs2 on nand support */
/* No command line, one static partition */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nand0"
#define CONFIG_JFFS2_PART_SIZE 0x01000000
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
diff --git a/include/configs/sc520_cdp.h b/include/configs/sc520_cdp.h
index 9f2357b..960350c 100644
--- a/include/configs/sc520_cdp.h
+++ b/include/configs/sc520_cdp.h
@@ -28,6 +28,8 @@
#ifndef __CONFIG_H
#define __CONFIG_H
+#define CONFIG_SKIP_RELOCATE_UBOOT
+
#define GRUSS_TESTING
/*
* High Level Configuration Options
@@ -35,7 +37,7 @@
*/
#define CONFIG_X86 1 /* This is a X86 CPU */
-#define CONFIG_SC520 1 /* Include support for AMD SC520 */
+#define CONFIG_SYS_SC520 1 /* Include support for AMD SC520 */
#define CONFIG_ALI152X 1 /* Include support for Ali 152x SIO */
#define CONFIG_SYS_SDRAM_PRECHARGE_DELAY 6 /* 6T */
@@ -47,12 +49,14 @@
#define CONFIG_SYS_SDRAM_CAS_LATENCY_3T
#define CONFIG_SYS_SC520_HIGH_SPEED 0 /* 100 or 133MHz */
-#undef CONFIG_SYS_RESET_SC520 /* use SC520 MMCR's to reset cpu */
-#undef CONFIG_SYS_TIMER_SC520 /* use SC520 swtimers */
-#define CONFIG_SYS_TIMER_GENERIC 1 /* use the i8254 PIT timers */
-#undef CONFIG_SYS_TIMER_TSC /* use the Pentium TSC timers */
+#undef CONFIG_SYS_SC520_RESET /* use SC520 MMCR's to reset cpu */
+#undef CONFIG_SYS_SC520_TIMER /* use SC520 swtimers */
+#define CONFIG_SYS_GENERIC_TIMER 1 /* use the i8254 PIT timers */
+#undef CONFIG_SYS_TSC_TIMER /* use the Pentium TSC timers */
#define CONFIG_SYS_USE_SIO_UART 0 /* prefer the uarts on the SIO to those
* in the SC520 on the CDP */
+#define CONFIG_SYS_PCAT_INTERRUPTS
+#define CONFIG_SYS_NUM_IRQS 16
#define CONFIG_SYS_STACK_SIZE 0x8000 /* Size of bootloader stack */
@@ -147,22 +151,22 @@
#define CONFIG_SPI
#define CONFIG_ENV_SIZE 0x4000 /* Total Size of Environment EEPROM 16k is SPI is used or 128 bytes if MW is used*/
#define CONFIG_ENV_OFFSET 0
-#define CONFIG_SC520_CDP_USE_SPI /* Store configuration in the SPI part */
-#undef CONFIG_SC520_CDP_USE_MW /* Store configuration in the MicroWire part */
+#define CONFIG_SYS_SC520_CDP_USE_SPI /* Store configuration in the SPI part */
+#undef CONFIG_SYS_SC520_CDP_USE_MW /* Store configuration in the MicroWire part */
#define CONFIG_SPI_X 1
/*
* JFFS2 partitions
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
/* mtdparts command line support */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=SC520CDP Flash Bank #0"
#define MTDPARTS_DEFAULT "mtdparts=SC520CDP Flash Bank #0:-(jffs2)"
*/
diff --git a/include/configs/sc520_spunk.h b/include/configs/sc520_spunk.h
index 50af732..2445a34 100644
--- a/include/configs/sc520_spunk.h
+++ b/include/configs/sc520_spunk.h
@@ -28,13 +28,15 @@
#ifndef __CONFIG_H
#define __CONFIG_H
+#define CONFIG_SKIP_RELOCATE_UBOOT
+
/*
* High Level Configuration Options
* (easy to change)
*/
#define CONFIG_X86 1 /* This is a X86 CPU */
-#define CONFIG_SC520 1 /* Include support for AMD SC520 */
+#define CONFIG_SYS_SC520 1 /* Include support for AMD SC520 */
#define CONFIG_SYS_SDRAM_PRECHARGE_DELAY 6 /* 6T */
#define CONFIG_SYS_SDRAM_REFRESH_RATE 78 /* 7.8uS (choices are 7.8, 15.6, 31.2 or 62.5uS) */
@@ -45,10 +47,12 @@
#define CONFIG_SYS_SDRAM_CAS_LATENCY_3T
#define CONFIG_SYS_SC520_HIGH_SPEED 0 /* 100 or 133MHz */
-#undef CONFIG_SYS_RESET_SC520 /* use SC520 MMCR's to reset cpu */
-#undef CONFIG_SYS_TIMER_SC520 /* use SC520 swtimers */
-#define CONFIG_SYS_TIMER_GENERIC 1 /* use the i8254 PIT timers */
-#undef CONFIG_SYS_TIMER_TSC /* use the Pentium TSC timers */
+#undef CONFIG_SYS_SC520_RESET /* use SC520 MMCR's to reset cpu */
+#undef CONFIG_SYS_SC520_TIMER /* use SC520 swtimers */
+#define CONFIG_SYS_GENERIC_TIMER 1 /* use the i8254 PIT timers */
+#undef CONFIG_SYS_TSC_TIMER /* use the Pentium TSC timers */
+#define CONFIG_SYS_PCAT_INTERRUPTS
+#define CONFIG_SYS_NUM_IRQS 16
#define CONFIG_SYS_STACK_SIZE 0x8000 /* Size of bootloader stack */
@@ -173,7 +177,7 @@
*
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
@@ -181,7 +185,7 @@
/* mtdparts command line support */
/* Note: fake mtd_id used, no linux mtd map file */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=sc520_spunk-0"
#define MTDPARTS_DEFAULT "mtdparts=sc520_spunk-0:-(jffs2)"
*/
diff --git a/include/configs/smmaco4.h b/include/configs/smmaco4.h
index a3f2677..35f3e3a 100644
--- a/include/configs/smmaco4.h
+++ b/include/configs/smmaco4.h
@@ -214,7 +214,7 @@
#define CONFIG_SYS_FLASH_WRITE_TOUT 500 /* Flash Write Timeout (in ms) */
/* Dynamic MTD partition support */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=TQM5200-0"
#define MTDPARTS_DEFAULT "mtdparts=TQM5200-0:640k(firmware)," \
"1408k(kernel)," \
diff --git a/include/configs/trab.h b/include/configs/trab.h
index 0a7a73d..8f13c35 100644
--- a/include/configs/trab.h
+++ b/include/configs/trab.h
@@ -375,7 +375,7 @@
#define CONFIG_SYS_MONITOR_LEN (256 << 10)
/* Dynamic MTD partition support */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=0"
/* production flash layout */
diff --git a/include/configs/v37.h b/include/configs/v37.h
index a6b0f0d..7f1670e 100644
--- a/include/configs/v37.h
+++ b/include/configs/v37.h
@@ -106,7 +106,7 @@
*
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor1"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
@@ -114,7 +114,7 @@
/* mtdparts command line support */
/* Note: fake mtd_id used, no linux mtd map file */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor1=v37-1"
#define MTDPARTS_DEFAULT "mtdparts=v37-1:-(jffs2)"
*/
diff --git a/include/configs/v38b.h b/include/configs/v38b.h
index fc7128e..92bcdb3 100644
--- a/include/configs/v38b.h
+++ b/include/configs/v38b.h
@@ -40,6 +40,7 @@
#define CONFIG_BOARD_EARLY_INIT_R 1 /* do board-specific init */
#define CONFIG_BOARD_EARLY_INIT_F 1 /* do board-specific init */
+#define CONFIG_MISC_INIT_R
#define CONFIG_SYS_XLB_PIPELINING 1 /* gives better performance */
diff --git a/include/configs/vct.h b/include/configs/vct.h
index 391535e..5371e2d 100644
--- a/include/configs/vct.h
+++ b/include/configs/vct.h
@@ -286,7 +286,7 @@ int vct_gpio_get(int pin);
#define CONFIG_CMD_UBI
#define CONFIG_RBTREE
#define CONFIG_MTD_PARTITIONS
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "onenand0=onenand"
#define MTDPARTS_DEFAULT "mtdparts=onenand:128k(u-boot)," \
diff --git a/include/configs/virtlab2.h b/include/configs/virtlab2.h
index 7b61c82..021012d 100644
--- a/include/configs/virtlab2.h
+++ b/include/configs/virtlab2.h
@@ -225,7 +225,7 @@
/*-----------------------------------------------------------------------
* Dynamic MTD partition support
*/
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=TQM8xxL-0"
#define MTDPARTS_DEFAULT "mtdparts=TQM8xxL-0:256k(u-boot)," \
diff --git a/include/configs/voiceblue.h b/include/configs/voiceblue.h
index f460610..cadd906 100644
--- a/include/configs/voiceblue.h
+++ b/include/configs/voiceblue.h
@@ -189,7 +189,7 @@
/*
* JFFS2 partitions (mtdparts command line support)
*/
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=omapflash.0"
#define MTDPARTS_DEFAULT "mtdparts=omapflash.0:256k(u-boot),64k(env),64k(r_env),16192k(data0),-(data1)"
diff --git a/include/configs/xilinx-ppc.h b/include/configs/xilinx-ppc.h
index e7daa07..e3ea84b 100644
--- a/include/configs/xilinx-ppc.h
+++ b/include/configs/xilinx-ppc.h
@@ -41,7 +41,7 @@
#define CONFIG_CMD_IRQ
#define CONFIG_CMD_REGINFO
#undef CONFIG_CMD_JFFS2
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#undef CONFIG_CMD_SPI
#undef CONFIG_CMD_I2C
#undef CONFIG_CMD_DTT
@@ -108,7 +108,7 @@
#define CONFIG_SYS_MAX_FLASH_BANKS 1
#define CONFIG_SYS_FLASH_PROTECTION
#define CONFIG_CMD_JFFS2
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#else
#define CONFIG_ENV_IS_NOWHERE
#define CONFIG_SYS_NO_FLASH
diff --git a/include/configs/xsengine.h b/include/configs/xsengine.h
index 6761438..5d13f96 100644
--- a/include/configs/xsengine.h
+++ b/include/configs/xsengine.h
@@ -62,7 +62,7 @@
* JFFS2 partitions
*/
/* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
#define CONFIG_JFFS2_DEV "nor0"
#define CONFIG_JFFS2_PART_SIZE 0xFFFFFFFF
#define CONFIG_JFFS2_PART_OFFSET 0x00000000
@@ -70,7 +70,7 @@
/* mtdparts command line support */
/* Note: fake mtd_id used, no linux mtd map file */
/*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nor0=xsengine-0"
#define MTDPARTS_DEFAULT "mtdparts=xsengine-0:256k(uboot),1m(kernel1),8m(kernel2)"
*/
diff --git a/include/linux/lzo.h b/include/linux/lzo.h
new file mode 100644
index 0000000..d793497
--- /dev/null
+++ b/include/linux/lzo.h
@@ -0,0 +1,44 @@
+#ifndef __LZO_H__
+#define __LZO_H__
+/*
+ * LZO Public Kernel Interface
+ * A mini subset of the LZO real-time data compression library
+ *
+ * Copyright (C) 1996-2005 Markus F.X.J. Oberhumer <markus@oberhumer.com>
+ *
+ * The full LZO package can be found at:
+ * http://www.oberhumer.com/opensource/lzo/
+ *
+ * Changed for kernel use by:
+ * Nitin Gupta <nitingupta910@gmail.com>
+ * Richard Purdie <rpurdie@openedhand.com>
+ */
+
+#define LZO1X_MEM_COMPRESS (16384 * sizeof(unsigned char *))
+#define LZO1X_1_MEM_COMPRESS LZO1X_MEM_COMPRESS
+
+#define lzo1x_worst_compress(x) ((x) + ((x) / 16) + 64 + 3)
+
+/* This requires 'workmem' of size LZO1X_1_MEM_COMPRESS */
+int lzo1x_1_compress(const unsigned char *src, size_t src_len,
+ unsigned char *dst, size_t *dst_len, void *wrkmem);
+
+/* safe decompression with overrun testing */
+int lzo1x_decompress_safe(const unsigned char *src, size_t src_len,
+ unsigned char *dst, size_t *dst_len);
+
+/*
+ * Return values (< 0 = Error)
+ */
+#define LZO_E_OK 0
+#define LZO_E_ERROR (-1)
+#define LZO_E_OUT_OF_MEMORY (-2)
+#define LZO_E_NOT_COMPRESSIBLE (-3)
+#define LZO_E_INPUT_OVERRUN (-4)
+#define LZO_E_OUTPUT_OVERRUN (-5)
+#define LZO_E_LOOKBEHIND_OVERRUN (-6)
+#define LZO_E_EOF_NOT_FOUND (-7)
+#define LZO_E_INPUT_NOT_CONSUMED (-8)
+#define LZO_E_NOT_YET_IMPLEMENTED (-9)
+
+#endif
diff --git a/include/linux/math64.h b/include/linux/math64.h
new file mode 100644
index 0000000..6d760d7
--- /dev/null
+++ b/include/linux/math64.h
@@ -0,0 +1,85 @@
+#ifndef _LINUX_MATH64_H
+#define _LINUX_MATH64_H
+
+#include <linux/types.h>
+
+#if BITS_PER_LONG == 64
+
+/**
+ * div_u64_rem - unsigned 64bit divide with 32bit divisor with remainder
+ *
+ * This is commonly provided by 32bit archs to provide an optimized 64bit
+ * divide.
+ */
+static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
+{
+ *remainder = dividend % divisor;
+ return dividend / divisor;
+}
+
+/**
+ * div_s64_rem - signed 64bit divide with 32bit divisor with remainder
+ */
+static inline s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
+{
+ *remainder = dividend % divisor;
+ return dividend / divisor;
+}
+
+/**
+ * div64_u64 - unsigned 64bit divide with 64bit divisor
+ */
+static inline u64 div64_u64(u64 dividend, u64 divisor)
+{
+ return dividend / divisor;
+}
+
+#elif BITS_PER_LONG == 32
+
+#ifndef div_u64_rem
+static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
+{
+ *remainder = do_div(dividend, divisor);
+ return dividend;
+}
+#endif
+
+#ifndef div_s64_rem
+extern s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder);
+#endif
+
+#ifndef div64_u64
+extern u64 div64_u64(u64 dividend, u64 divisor);
+#endif
+
+#endif /* BITS_PER_LONG */
+
+/**
+ * div_u64 - unsigned 64bit divide with 32bit divisor
+ *
+ * This is the most common 64bit divide and should be used if possible,
+ * as many 32bit archs can optimize this variant better than a full 64bit
+ * divide.
+ */
+#ifndef div_u64
+static inline u64 div_u64(u64 dividend, u32 divisor)
+{
+ u32 remainder;
+ return div_u64_rem(dividend, divisor, &remainder);
+}
+#endif
+
+/**
+ * div_s64 - signed 64bit divide with 32bit divisor
+ */
+#ifndef div_s64
+static inline s64 div_s64(s64 dividend, s32 divisor)
+{
+ s32 remainder;
+ return div_s64_rem(dividend, divisor, &remainder);
+}
+#endif
+
+u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder);
+
+#endif /* _LINUX_MATH64_H */
diff --git a/include/linux/unaligned/access_ok.h b/include/linux/unaligned/access_ok.h
new file mode 100644
index 0000000..5f46eee
--- /dev/null
+++ b/include/linux/unaligned/access_ok.h
@@ -0,0 +1,66 @@
+#ifndef _LINUX_UNALIGNED_ACCESS_OK_H
+#define _LINUX_UNALIGNED_ACCESS_OK_H
+
+#include <asm/byteorder.h>
+
+static inline u16 get_unaligned_le16(const void *p)
+{
+ return le16_to_cpup((__le16 *)p);
+}
+
+static inline u32 get_unaligned_le32(const void *p)
+{
+ return le32_to_cpup((__le32 *)p);
+}
+
+static inline u64 get_unaligned_le64(const void *p)
+{
+ return le64_to_cpup((__le64 *)p);
+}
+
+static inline u16 get_unaligned_be16(const void *p)
+{
+ return be16_to_cpup((__be16 *)p);
+}
+
+static inline u32 get_unaligned_be32(const void *p)
+{
+ return be32_to_cpup((__be32 *)p);
+}
+
+static inline u64 get_unaligned_be64(const void *p)
+{
+ return be64_to_cpup((__be64 *)p);
+}
+
+static inline void put_unaligned_le16(u16 val, void *p)
+{
+ *((__le16 *)p) = cpu_to_le16(val);
+}
+
+static inline void put_unaligned_le32(u32 val, void *p)
+{
+ *((__le32 *)p) = cpu_to_le32(val);
+}
+
+static inline void put_unaligned_le64(u64 val, void *p)
+{
+ *((__le64 *)p) = cpu_to_le64(val);
+}
+
+static inline void put_unaligned_be16(u16 val, void *p)
+{
+ *((__be16 *)p) = cpu_to_be16(val);
+}
+
+static inline void put_unaligned_be32(u32 val, void *p)
+{
+ *((__be32 *)p) = cpu_to_be32(val);
+}
+
+static inline void put_unaligned_be64(u64 val, void *p)
+{
+ *((__be64 *)p) = cpu_to_be64(val);
+}
+
+#endif /* _LINUX_UNALIGNED_ACCESS_OK_H */
diff --git a/include/linux/unaligned/generic.h b/include/linux/unaligned/generic.h
new file mode 100644
index 0000000..cc688e1
--- /dev/null
+++ b/include/linux/unaligned/generic.h
@@ -0,0 +1,71 @@
+#ifndef _LINUX_UNALIGNED_GENERIC_H
+#define _LINUX_UNALIGNED_GENERIC_H
+
+/* define __force to nothing in U-Boot */
+#define __force
+
+/*
+ * Cause a link-time error if we try an unaligned access other than
+ * 1,2,4 or 8 bytes long
+ */
+extern void __bad_unaligned_access_size(void);
+
+#define __get_unaligned_le(ptr) ((__force typeof(*(ptr)))({ \
+ __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_le16((ptr)), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_le32((ptr)), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_le64((ptr)), \
+ __bad_unaligned_access_size())))); \
+ }))
+
+#define __get_unaligned_be(ptr) ((__force typeof(*(ptr)))({ \
+ __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_be16((ptr)), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_be32((ptr)), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_be64((ptr)), \
+ __bad_unaligned_access_size())))); \
+ }))
+
+#define __put_unaligned_le(val, ptr) ({ \
+ void *__gu_p = (ptr); \
+ switch (sizeof(*(ptr))) { \
+ case 1: \
+ *(u8 *)__gu_p = (__force u8)(val); \
+ break; \
+ case 2: \
+ put_unaligned_le16((__force u16)(val), __gu_p); \
+ break; \
+ case 4: \
+ put_unaligned_le32((__force u32)(val), __gu_p); \
+ break; \
+ case 8: \
+ put_unaligned_le64((__force u64)(val), __gu_p); \
+ break; \
+ default: \
+ __bad_unaligned_access_size(); \
+ break; \
+ } \
+ (void)0; })
+
+#define __put_unaligned_be(val, ptr) ({ \
+ void *__gu_p = (ptr); \
+ switch (sizeof(*(ptr))) { \
+ case 1: \
+ *(u8 *)__gu_p = (__force u8)(val); \
+ break; \
+ case 2: \
+ put_unaligned_be16((__force u16)(val), __gu_p); \
+ break; \
+ case 4: \
+ put_unaligned_be32((__force u32)(val), __gu_p); \
+ break; \
+ case 8: \
+ put_unaligned_be64((__force u64)(val), __gu_p); \
+ break; \
+ default: \
+ __bad_unaligned_access_size(); \
+ break; \
+ } \
+ (void)0; })
+
+#endif /* _LINUX_UNALIGNED_GENERIC_H */
diff --git a/include/net.h b/include/net.h
index b192db1..5a1d36e 100644
--- a/include/net.h
+++ b/include/net.h
@@ -120,6 +120,9 @@ extern struct eth_device *eth_get_dev_by_name(char *devname); /* get device */
extern struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */
extern int eth_get_dev_index (void); /* get the device index */
extern void eth_set_enetaddr(int num, char* a); /* Set new MAC address */
+extern void eth_parse_enetaddr(const char *addr, uchar *enetaddr);
+extern int eth_getenv_enetaddr(char *name, uchar *enetaddr);
+extern int eth_setenv_enetaddr(char *name, const uchar *enetaddr);
extern int eth_init(bd_t *bis); /* Initialize the device */
extern int eth_send(volatile void *packet, int length); /* Send a packet */
@@ -408,9 +411,6 @@ extern int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, i
/* Processes a received packet */
extern void NetReceive(volatile uchar *, int);
-/* Print an IP address on the console */
-extern void print_IPaddr (IPaddr_t);
-
/*
* The following functions are a bit ugly, but necessary to deal with
* alignment restrictions on ARM.
diff --git a/include/ubi_uboot.h b/include/ubi_uboot.h
index b415219..74312ab 100644
--- a/include/ubi_uboot.h
+++ b/include/ubi_uboot.h
@@ -18,7 +18,12 @@
#include <malloc.h>
#include <div64.h>
#include <linux/crc32.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/rbtree.h>
+#include <linux/string.h>
#include <linux/mtd/mtd.h>
+#include <linux/mtd/ubi.h>
#ifdef CONFIG_CMD_ONENAND
#include <onenand_uboot.h>
@@ -193,7 +198,7 @@ static inline long IS_ERR(const void *ptr)
/* module */
#define THIS_MODULE 0
-#define try_module_get(...) 0
+#define try_module_get(...) 1
#define module_put(...) do { } while (0)
#define module_init(...)
#define module_exit(...)
@@ -206,7 +211,9 @@ static inline long IS_ERR(const void *ptr)
#define MODULE_AUTHOR(...)
#define MODULE_LICENSE(...)
+#ifndef __UBIFS_H__
#include "../drivers/mtd/ubi/ubi.h"
+#endif
/* functions */
extern int ubi_mtd_param_parse(const char *val, struct kernel_param *kp);
diff --git a/lib_arm/board.c b/lib_arm/board.c
index 09eaaf2..3dfaec0 100644
--- a/lib_arm/board.c
+++ b/lib_arm/board.c
@@ -73,7 +73,7 @@ const char version_string[] =
U_BOOT_VERSION" (" U_BOOT_DATE " - " U_BOOT_TIME ")"CONFIG_IDENT_STRING;
#ifdef CONFIG_DRIVER_CS8900
-extern void cs8900_get_enetaddr (uchar * addr);
+extern void cs8900_get_enetaddr (void);
#endif
#ifdef CONFIG_DRIVER_RTL8019
@@ -379,40 +379,8 @@ void start_armboot (void)
/* IP Address */
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
- /* MAC Address */
- {
- int i;
- ulong reg;
- char *s, *e;
- char tmp[64];
-
- i = getenv_r ("ethaddr", tmp, sizeof (tmp));
- s = (i > 0) ? tmp : NULL;
-
- for (reg = 0; reg < 6; ++reg) {
- gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
-
-#ifdef CONFIG_HAS_ETH1
- i = getenv_r ("eth1addr", tmp, sizeof (tmp));
- s = (i > 0) ? tmp : NULL;
-
- for (reg = 0; reg < 6; ++reg) {
- gd->bd->bi_enet1addr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
-#endif
- }
-
devices_init (); /* get the devices list going. */
-#ifdef CONFIG_CMC_PU2
- load_sernum_ethaddr ();
-#endif /* CONFIG_CMC_PU2 */
-
jumptable_init ();
#if defined(CONFIG_API)
@@ -432,19 +400,26 @@ void start_armboot (void)
/* Perform network card initialisation if necessary */
#ifdef CONFIG_DRIVER_TI_EMAC
+ /* XXX: this needs to be moved to board init */
extern void davinci_eth_set_mac_addr (const u_int8_t *addr);
if (getenv ("ethaddr")) {
- davinci_eth_set_mac_addr(gd->bd->bi_enetaddr);
+ uchar enetaddr[6];
+ eth_getenv_enetaddr("ethaddr", enetaddr);
+ davinci_eth_set_mac_addr(enetaddr);
}
#endif
#ifdef CONFIG_DRIVER_CS8900
- cs8900_get_enetaddr (gd->bd->bi_enetaddr);
+ /* XXX: this needs to be moved to board init */
+ cs8900_get_enetaddr ();
#endif
#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
+ /* XXX: this needs to be moved to board init */
if (getenv ("ethaddr")) {
- smc_set_mac_addr(gd->bd->bi_enetaddr);
+ uchar enetaddr[6];
+ eth_getenv_enetaddr("ethaddr", enetaddr);
+ smc_set_mac_addr(enetaddr);
}
#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */
diff --git a/lib_blackfin/board.c b/lib_blackfin/board.c
index c223711..537f69a 100644
--- a/lib_blackfin/board.c
+++ b/lib_blackfin/board.c
@@ -106,10 +106,6 @@ static void display_global_data(void)
printf(" \\-bd: %x\n", gd->bd);
printf(" |-bi_baudrate: %x\n", bd->bi_baudrate);
printf(" |-bi_ip_addr: %x\n", bd->bi_ip_addr);
- printf(" |-bi_enetaddr: %x %x %x %x %x %x\n",
- bd->bi_enetaddr[0], bd->bi_enetaddr[1],
- bd->bi_enetaddr[2], bd->bi_enetaddr[3],
- bd->bi_enetaddr[4], bd->bi_enetaddr[5]);
printf(" |-bi_boot_params: %x\n", bd->bi_boot_params);
printf(" |-bi_memstart: %x\n", bd->bi_memstart);
printf(" |-bi_memsize: %x\n", bd->bi_memsize);
@@ -338,35 +334,6 @@ void board_init_r(gd_t * id, ulong dest_addr)
/* relocate environment function pointers etc. */
env_relocate();
-#ifdef CONFIG_CMD_NET
- /* board MAC address */
- s = getenv("ethaddr");
- if (s == NULL) {
-# ifndef CONFIG_ETHADDR
-# if 0
- if (!board_get_enetaddr(bd->bi_enetaddr)) {
- char nid[20];
- sprintf(nid, "%02X:%02X:%02X:%02X:%02X:%02X",
- bd->bi_enetaddr[0], bd->bi_enetaddr[1],
- bd->bi_enetaddr[2], bd->bi_enetaddr[3],
- bd->bi_enetaddr[4], bd->bi_enetaddr[5]);
- setenv("ethaddr", nid);
- }
-# endif
-# endif
- } else {
- int i;
- char *e;
- for (i = 0; i < 6; ++i) {
- bd->bi_enetaddr[i] = simple_strtoul(s, &e, 16);
- s = (*e) ? e + 1 : e;
- }
- }
-
- /* IP Address */
- bd->bi_ip_addr = getenv_IPaddr("ipaddr");
-#endif
-
/* Initialize devices */
devices_init();
jumptable_init();
@@ -393,21 +360,10 @@ void board_init_r(gd_t * id, ulong dest_addr)
#endif
#ifdef CONFIG_CMD_NET
+ /* IP Address */
+ bd->bi_ip_addr = getenv_IPaddr("ipaddr");
printf("Net: ");
eth_initialize(gd->bd);
- if ((s = getenv("ethaddr"))) {
-# ifndef CONFIG_NET_MULTI
- size_t i;
- char *e;
- for (i = 0; i < 6; ++i) {
- bd->bi_enetaddr[i] = simple_strtoul(s, &e, 16);
- s = (*e) ? e + 1 : e;
- }
-# endif
- printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
- bd->bi_enetaddr[0], bd->bi_enetaddr[1], bd->bi_enetaddr[2],
- bd->bi_enetaddr[3], bd->bi_enetaddr[4], bd->bi_enetaddr[5]);
- }
#endif
display_global_data();
diff --git a/lib_generic/lzo/Makefile b/lib_generic/lzo/Makefile
new file mode 100644
index 0000000..5dd1bf5
--- /dev/null
+++ b/lib_generic/lzo/Makefile
@@ -0,0 +1,46 @@
+#
+# (C) Copyright 2008
+# Stefan Roese, DENX Software Engineering, sr@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)liblzo.a
+
+SOBJS =
+
+COBJS-$(CONFIG_LZO) += lzo1x_decompress.o
+
+COBJS = $(COBJS-y)
+SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
+
+$(LIB): $(obj).depend $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/lib_generic/lzo/lzo1x_decompress.c b/lib_generic/lzo/lzo1x_decompress.c
new file mode 100644
index 0000000..2780e11
--- /dev/null
+++ b/lib_generic/lzo/lzo1x_decompress.c
@@ -0,0 +1,245 @@
+/*
+ * LZO1X Decompressor from MiniLZO
+ *
+ * Copyright (C) 1996-2005 Markus F.X.J. Oberhumer <markus@oberhumer.com>
+ *
+ * The full LZO package can be found at:
+ * http://www.oberhumer.com/opensource/lzo/
+ *
+ * Changed for kernel use by:
+ * Nitin Gupta <nitingupta910@gmail.com>
+ * Richard Purdie <rpurdie@openedhand.com>
+ */
+
+#include <common.h>
+#include <linux/lzo.h>
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+#include "lzodefs.h"
+
+#define HAVE_IP(x, ip_end, ip) ((size_t)(ip_end - ip) < (x))
+#define HAVE_OP(x, op_end, op) ((size_t)(op_end - op) < (x))
+#define HAVE_LB(m_pos, out, op) (m_pos < out || m_pos >= op)
+
+#define COPY4(dst, src) \
+ put_unaligned(get_unaligned((const u32 *)(src)), (u32 *)(dst))
+
+int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
+ unsigned char *out, size_t *out_len)
+{
+ const unsigned char * const ip_end = in + in_len;
+ unsigned char * const op_end = out + *out_len;
+ const unsigned char *ip = in, *m_pos;
+ unsigned char *op = out;
+ size_t t;
+
+ *out_len = 0;
+
+ if (*ip > 17) {
+ t = *ip++ - 17;
+ if (t < 4)
+ goto match_next;
+ if (HAVE_OP(t, op_end, op))
+ goto output_overrun;
+ if (HAVE_IP(t + 1, ip_end, ip))
+ goto input_overrun;
+ do {
+ *op++ = *ip++;
+ } while (--t > 0);
+ goto first_literal_run;
+ }
+
+ while ((ip < ip_end)) {
+ t = *ip++;
+ if (t >= 16)
+ goto match;
+ if (t == 0) {
+ if (HAVE_IP(1, ip_end, ip))
+ goto input_overrun;
+ while (*ip == 0) {
+ t += 255;
+ ip++;
+ if (HAVE_IP(1, ip_end, ip))
+ goto input_overrun;
+ }
+ t += 15 + *ip++;
+ }
+ if (HAVE_OP(t + 3, op_end, op))
+ goto output_overrun;
+ if (HAVE_IP(t + 4, ip_end, ip))
+ goto input_overrun;
+
+ COPY4(op, ip);
+ op += 4;
+ ip += 4;
+ if (--t > 0) {
+ if (t >= 4) {
+ do {
+ COPY4(op, ip);
+ op += 4;
+ ip += 4;
+ t -= 4;
+ } while (t >= 4);
+ if (t > 0) {
+ do {
+ *op++ = *ip++;
+ } while (--t > 0);
+ }
+ } else {
+ do {
+ *op++ = *ip++;
+ } while (--t > 0);
+ }
+ }
+
+first_literal_run:
+ t = *ip++;
+ if (t >= 16)
+ goto match;
+ m_pos = op - (1 + M2_MAX_OFFSET);
+ m_pos -= t >> 2;
+ m_pos -= *ip++ << 2;
+
+ if (HAVE_LB(m_pos, out, op))
+ goto lookbehind_overrun;
+
+ if (HAVE_OP(3, op_end, op))
+ goto output_overrun;
+ *op++ = *m_pos++;
+ *op++ = *m_pos++;
+ *op++ = *m_pos;
+
+ goto match_done;
+
+ do {
+match:
+ if (t >= 64) {
+ m_pos = op - 1;
+ m_pos -= (t >> 2) & 7;
+ m_pos -= *ip++ << 3;
+ t = (t >> 5) - 1;
+ if (HAVE_LB(m_pos, out, op))
+ goto lookbehind_overrun;
+ if (HAVE_OP(t + 3 - 1, op_end, op))
+ goto output_overrun;
+ goto copy_match;
+ } else if (t >= 32) {
+ t &= 31;
+ if (t == 0) {
+ if (HAVE_IP(1, ip_end, ip))
+ goto input_overrun;
+ while (*ip == 0) {
+ t += 255;
+ ip++;
+ if (HAVE_IP(1, ip_end, ip))
+ goto input_overrun;
+ }
+ t += 31 + *ip++;
+ }
+ m_pos = op - 1;
+ m_pos -= get_unaligned_le16(ip) >> 2;
+ ip += 2;
+ } else if (t >= 16) {
+ m_pos = op;
+ m_pos -= (t & 8) << 11;
+
+ t &= 7;
+ if (t == 0) {
+ if (HAVE_IP(1, ip_end, ip))
+ goto input_overrun;
+ while (*ip == 0) {
+ t += 255;
+ ip++;
+ if (HAVE_IP(1, ip_end, ip))
+ goto input_overrun;
+ }
+ t += 7 + *ip++;
+ }
+ m_pos -= get_unaligned_le16(ip) >> 2;
+ ip += 2;
+ if (m_pos == op)
+ goto eof_found;
+ m_pos -= 0x4000;
+ } else {
+ m_pos = op - 1;
+ m_pos -= t >> 2;
+ m_pos -= *ip++ << 2;
+
+ if (HAVE_LB(m_pos, out, op))
+ goto lookbehind_overrun;
+ if (HAVE_OP(2, op_end, op))
+ goto output_overrun;
+
+ *op++ = *m_pos++;
+ *op++ = *m_pos;
+ goto match_done;
+ }
+
+ if (HAVE_LB(m_pos, out, op))
+ goto lookbehind_overrun;
+ if (HAVE_OP(t + 3 - 1, op_end, op))
+ goto output_overrun;
+
+ if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) {
+ COPY4(op, m_pos);
+ op += 4;
+ m_pos += 4;
+ t -= 4 - (3 - 1);
+ do {
+ COPY4(op, m_pos);
+ op += 4;
+ m_pos += 4;
+ t -= 4;
+ } while (t >= 4);
+ if (t > 0)
+ do {
+ *op++ = *m_pos++;
+ } while (--t > 0);
+ } else {
+copy_match:
+ *op++ = *m_pos++;
+ *op++ = *m_pos++;
+ do {
+ *op++ = *m_pos++;
+ } while (--t > 0);
+ }
+match_done:
+ t = ip[-2] & 3;
+ if (t == 0)
+ break;
+match_next:
+ if (HAVE_OP(t, op_end, op))
+ goto output_overrun;
+ if (HAVE_IP(t + 1, ip_end, ip))
+ goto input_overrun;
+
+ *op++ = *ip++;
+ if (t > 1) {
+ *op++ = *ip++;
+ if (t > 2)
+ *op++ = *ip++;
+ }
+
+ t = *ip++;
+ } while (ip < ip_end);
+ }
+
+ *out_len = op - out;
+ return LZO_E_EOF_NOT_FOUND;
+
+eof_found:
+ *out_len = op - out;
+ return (ip == ip_end ? LZO_E_OK :
+ (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
+input_overrun:
+ *out_len = op - out;
+ return LZO_E_INPUT_OVERRUN;
+
+output_overrun:
+ *out_len = op - out;
+ return LZO_E_OUTPUT_OVERRUN;
+
+lookbehind_overrun:
+ *out_len = op - out;
+ return LZO_E_LOOKBEHIND_OVERRUN;
+}
diff --git a/lib_generic/lzo/lzodefs.h b/lib_generic/lzo/lzodefs.h
new file mode 100644
index 0000000..b6d482c
--- /dev/null
+++ b/lib_generic/lzo/lzodefs.h
@@ -0,0 +1,43 @@
+/*
+ * lzodefs.h -- architecture, OS and compiler specific defines
+ *
+ * Copyright (C) 1996-2005 Markus F.X.J. Oberhumer <markus@oberhumer.com>
+ *
+ * The full LZO package can be found at:
+ * http://www.oberhumer.com/opensource/lzo/
+ *
+ * Changed for kernel use by:
+ * Nitin Gupta <nitingupta910@gmail.com>
+ * Richard Purdie <rpurdie@openedhand.com>
+ */
+
+#define LZO_VERSION 0x2020
+#define LZO_VERSION_STRING "2.02"
+#define LZO_VERSION_DATE "Oct 17 2005"
+
+#define M1_MAX_OFFSET 0x0400
+#define M2_MAX_OFFSET 0x0800
+#define M3_MAX_OFFSET 0x4000
+#define M4_MAX_OFFSET 0xbfff
+
+#define M1_MIN_LEN 2
+#define M1_MAX_LEN 2
+#define M2_MIN_LEN 3
+#define M2_MAX_LEN 8
+#define M3_MIN_LEN 3
+#define M3_MAX_LEN 33
+#define M4_MIN_LEN 3
+#define M4_MAX_LEN 9
+
+#define M1_MARKER 0
+#define M2_MARKER 64
+#define M3_MARKER 32
+#define M4_MARKER 16
+
+#define D_BITS 14
+#define D_MASK ((1u << D_BITS) - 1)
+#define D_HIGH ((D_MASK >> 1) + 1)
+
+#define DX2(p, s1, s2) (((((size_t)((p)[2]) << (s2)) ^ (p)[1]) \
+ << (s1)) ^ (p)[0])
+#define DX3(p, s1, s2, s3) ((DX2((p)+1, s2, s3) << (s1)) ^ (p)[0])
diff --git a/lib_generic/vsprintf.c b/lib_generic/vsprintf.c
index 767dde1..3ab1f5c 100644
--- a/lib_generic/vsprintf.c
+++ b/lib_generic/vsprintf.c
@@ -21,6 +21,31 @@
extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
#endif
+#ifdef CONFIG_SYS_64BIT_VSPRINTF
+# define NUM_TYPE long long
+#else
+# define NUM_TYPE long
+#endif
+#define noinline __attribute__((noinline))
+
+#define do_div(n, base) ({ \
+ unsigned int __res; \
+ __res = ((unsigned NUM_TYPE) n) % base; \
+ n = ((unsigned NUM_TYPE) n) / base; \
+ __res; \
+})
+
+const char hex_asc[] = "0123456789abcdef";
+#define hex_asc_lo(x) hex_asc[((x) & 0x0f)]
+#define hex_asc_hi(x) hex_asc[((x) & 0xf0) >> 4]
+
+static inline char *pack_hex_byte(char *buf, u8 byte)
+{
+ *buf++ = hex_asc_hi(byte);
+ *buf++ = hex_asc_lo(byte);
+ return buf;
+}
+
unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
{
unsigned long result = 0,value;
@@ -120,52 +145,132 @@ static int skip_atoi(const char **s)
return i;
}
+/* Decimal conversion is by far the most typical, and is used
+ * for /proc and /sys data. This directly impacts e.g. top performance
+ * with many processes running. We optimize it for speed
+ * using code from
+ * http://www.cs.uiowa.edu/~jones/bcd/decimal.html
+ * (with permission from the author, Douglas W. Jones). */
+
+/* Formats correctly any integer in [0,99999].
+ * Outputs from one to five digits depending on input.
+ * On i386 gcc 4.1.2 -O2: ~250 bytes of code. */
+static char* put_dec_trunc(char *buf, unsigned q)
+{
+ unsigned d3, d2, d1, d0;
+ d1 = (q>>4) & 0xf;
+ d2 = (q>>8) & 0xf;
+ d3 = (q>>12);
+
+ d0 = 6*(d3 + d2 + d1) + (q & 0xf);
+ q = (d0 * 0xcd) >> 11;
+ d0 = d0 - 10*q;
+ *buf++ = d0 + '0'; /* least significant digit */
+ d1 = q + 9*d3 + 5*d2 + d1;
+ if (d1 != 0) {
+ q = (d1 * 0xcd) >> 11;
+ d1 = d1 - 10*q;
+ *buf++ = d1 + '0'; /* next digit */
+
+ d2 = q + 2*d2;
+ if ((d2 != 0) || (d3 != 0)) {
+ q = (d2 * 0xd) >> 7;
+ d2 = d2 - 10*q;
+ *buf++ = d2 + '0'; /* next digit */
+
+ d3 = q + 4*d3;
+ if (d3 != 0) {
+ q = (d3 * 0xcd) >> 11;
+ d3 = d3 - 10*q;
+ *buf++ = d3 + '0'; /* next digit */
+ if (q != 0)
+ *buf++ = q + '0'; /* most sign. digit */
+ }
+ }
+ }
+ return buf;
+}
+/* Same with if's removed. Always emits five digits */
+static char* put_dec_full(char *buf, unsigned q)
+{
+ /* BTW, if q is in [0,9999], 8-bit ints will be enough, */
+ /* but anyway, gcc produces better code with full-sized ints */
+ unsigned d3, d2, d1, d0;
+ d1 = (q>>4) & 0xf;
+ d2 = (q>>8) & 0xf;
+ d3 = (q>>12);
+
+ /* Possible ways to approx. divide by 10 */
+ /* gcc -O2 replaces multiply with shifts and adds */
+ // (x * 0xcd) >> 11: 11001101 - shorter code than * 0x67 (on i386)
+ // (x * 0x67) >> 10: 1100111
+ // (x * 0x34) >> 9: 110100 - same
+ // (x * 0x1a) >> 8: 11010 - same
+ // (x * 0x0d) >> 7: 1101 - same, shortest code (on i386)
+
+ d0 = 6*(d3 + d2 + d1) + (q & 0xf);
+ q = (d0 * 0xcd) >> 11;
+ d0 = d0 - 10*q;
+ *buf++ = d0 + '0';
+ d1 = q + 9*d3 + 5*d2 + d1;
+ q = (d1 * 0xcd) >> 11;
+ d1 = d1 - 10*q;
+ *buf++ = d1 + '0';
+
+ d2 = q + 2*d2;
+ q = (d2 * 0xd) >> 7;
+ d2 = d2 - 10*q;
+ *buf++ = d2 + '0';
+
+ d3 = q + 4*d3;
+ q = (d3 * 0xcd) >> 11; /* - shorter code */
+ /* q = (d3 * 0x67) >> 10; - would also work */
+ d3 = d3 - 10*q;
+ *buf++ = d3 + '0';
+ *buf++ = q + '0';
+ return buf;
+}
+/* No inlining helps gcc to use registers better */
+static noinline char* put_dec(char *buf, unsigned NUM_TYPE num)
+{
+ while (1) {
+ unsigned rem;
+ if (num < 100000)
+ return put_dec_trunc(buf, num);
+ rem = do_div(num, 100000);
+ buf = put_dec_full(buf, rem);
+ }
+}
+
#define ZEROPAD 1 /* pad with zero */
#define SIGN 2 /* unsigned/signed long */
#define PLUS 4 /* show plus */
#define SPACE 8 /* space if plus */
#define LEFT 16 /* left justified */
-#define SPECIAL 32 /* 0x */
-#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
+#define SMALL 32 /* Must be 32 == 0x20 */
+#define SPECIAL 64 /* 0x */
-#ifdef CONFIG_SYS_64BIT_VSPRINTF
-#define do_div(n,base) ({ \
- unsigned int __res; \
- __res = ((unsigned long long) n) % base; \
- n = ((unsigned long long) n) / base; \
- __res; \
-})
-#else
-#define do_div(n,base) ({ \
- int __res; \
- __res = ((unsigned long) n) % base; \
- n = ((unsigned long) n) / base; \
- __res; \
-})
-#endif
-
-#ifdef CONFIG_SYS_64BIT_VSPRINTF
-static char * number(char * str, long long num, unsigned int base, int size, int precision ,int type)
-#else
-static char * number(char * str, long num, unsigned int base, int size, int precision ,int type)
-#endif
+static char *number(char *buf, unsigned NUM_TYPE num, int base, int size, int precision, int type)
{
- char c,sign,tmp[66];
- const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
+ /* we are called with base 8, 10 or 16, only, thus don't need "G..." */
+ static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
+
+ char tmp[66];
+ char sign;
+ char locase;
+ int need_pfx = ((type & SPECIAL) && base != 10);
int i;
- if (type & LARGE)
- digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ /* locase = 0 or 0x20. ORing digits or letters with 'locase'
+ * produces same digits or (maybe lowercased) letters */
+ locase = (type & SMALL);
if (type & LEFT)
type &= ~ZEROPAD;
- if (base < 2 || base > 36)
- return 0;
- c = (type & ZEROPAD) ? '0' : ' ';
sign = 0;
if (type & SIGN) {
- if (num < 0) {
+ if ((signed NUM_TYPE) num < 0) {
sign = '-';
- num = -num;
+ num = - (signed NUM_TYPE) num;
size--;
} else if (type & PLUS) {
sign = '+';
@@ -175,68 +280,231 @@ static char * number(char * str, long num, unsigned int base, int size, int prec
size--;
}
}
- if (type & SPECIAL) {
+ if (need_pfx) {
+ size--;
if (base == 16)
- size -= 2;
- else if (base == 8)
size--;
}
+
+ /* generate full string in tmp[], in reverse order */
i = 0;
if (num == 0)
- tmp[i++]='0';
- else while (num != 0)
- tmp[i++] = digits[do_div(num,base)];
+ tmp[i++] = '0';
+ /* Generic code, for any base:
+ else do {
+ tmp[i++] = (digits[do_div(num,base)] | locase);
+ } while (num != 0);
+ */
+ else if (base != 10) { /* 8 or 16 */
+ int mask = base - 1;
+ int shift = 3;
+ if (base == 16) shift = 4;
+ do {
+ tmp[i++] = (digits[((unsigned char)num) & mask] | locase);
+ num >>= shift;
+ } while (num);
+ } else { /* base 10 */
+ i = put_dec(tmp, num) - tmp;
+ }
+
+ /* printing 100 using %2d gives "100", not "00" */
if (i > precision)
precision = i;
+ /* leading space padding */
size -= precision;
- if (!(type&(ZEROPAD+LEFT)))
- while(size-->0)
- *str++ = ' ';
+ if (!(type & (ZEROPAD+LEFT)))
+ while(--size >= 0)
+ *buf++ = ' ';
+ /* sign */
if (sign)
- *str++ = sign;
- if (type & SPECIAL) {
- if (base==8)
- *str++ = '0';
- else if (base==16) {
- *str++ = '0';
- *str++ = digits[33];
- }
+ *buf++ = sign;
+ /* "0x" / "0" prefix */
+ if (need_pfx) {
+ *buf++ = '0';
+ if (base == 16)
+ *buf++ = ('X' | locase);
+ }
+ /* zero or space padding */
+ if (!(type & LEFT)) {
+ char c = (type & ZEROPAD) ? '0' : ' ';
+ while (--size >= 0)
+ *buf++ = c;
}
- if (!(type & LEFT))
- while (size-- > 0)
- *str++ = c;
- while (i < precision--)
- *str++ = '0';
- while (i-- > 0)
- *str++ = tmp[i];
- while (size-- > 0)
- *str++ = ' ';
- return str;
+ /* hmm even more zero padding? */
+ while (i <= --precision)
+ *buf++ = '0';
+ /* actual digits of result */
+ while (--i >= 0)
+ *buf++ = tmp[i];
+ /* trailing space padding */
+ while (--size >= 0)
+ *buf++ = ' ';
+ return buf;
}
-/* Forward decl. needed for IP address printing stuff... */
-int sprintf(char * buf, const char *fmt, ...);
+static char *string(char *buf, char *s, int field_width, int precision, int flags)
+{
+ int len, i;
-int vsprintf(char *buf, const char *fmt, va_list args)
+ if (s == 0)
+ s = "<NULL>";
+
+ len = strnlen(s, precision);
+
+ if (!(flags & LEFT))
+ while (len < field_width--)
+ *buf++ = ' ';
+ for (i = 0; i < len; ++i)
+ *buf++ = *s++;
+ while (len < field_width--)
+ *buf++ = ' ';
+ return buf;
+}
+
+#ifdef CONFIG_CMD_NET
+static char *mac_address_string(char *buf, u8 *addr, int field_width,
+ int precision, int flags)
{
- int len;
-#ifdef CONFIG_SYS_64BIT_VSPRINTF
- unsigned long long num;
-#else
- unsigned long num;
+ char mac_addr[6 * 3]; /* (6 * 2 hex digits), 5 colons and trailing zero */
+ char *p = mac_addr;
+ int i;
+
+ for (i = 0; i < 6; i++) {
+ p = pack_hex_byte(p, addr[i]);
+ if (!(flags & SPECIAL) && i != 5)
+ *p++ = ':';
+ }
+ *p = '\0';
+
+ return string(buf, mac_addr, field_width, precision, flags & ~SPECIAL);
+}
+
+static char *ip6_addr_string(char *buf, u8 *addr, int field_width,
+ int precision, int flags)
+{
+ char ip6_addr[8 * 5]; /* (8 * 4 hex digits), 7 colons and trailing zero */
+ char *p = ip6_addr;
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ p = pack_hex_byte(p, addr[2 * i]);
+ p = pack_hex_byte(p, addr[2 * i + 1]);
+ if (!(flags & SPECIAL) && i != 7)
+ *p++ = ':';
+ }
+ *p = '\0';
+
+ return string(buf, ip6_addr, field_width, precision, flags & ~SPECIAL);
+}
+
+static char *ip4_addr_string(char *buf, u8 *addr, int field_width,
+ int precision, int flags)
+{
+ char ip4_addr[4 * 4]; /* (4 * 3 decimal digits), 3 dots and trailing zero */
+ char temp[3]; /* hold each IP quad in reverse order */
+ char *p = ip4_addr;
+ int i, digits;
+
+ for (i = 0; i < 4; i++) {
+ digits = put_dec_trunc(temp, addr[i]) - temp;
+ /* reverse the digits in the quad */
+ while (digits--)
+ *p++ = temp[digits];
+ if (i != 3)
+ *p++ = '.';
+ }
+ *p = '\0';
+
+ return string(buf, ip4_addr, field_width, precision, flags & ~SPECIAL);
+}
#endif
- int i, base;
- char * str;
- const char *s;
+
+/*
+ * Show a '%p' thing. A kernel extension is that the '%p' is followed
+ * by an extra set of alphanumeric characters that are extended format
+ * specifiers.
+ *
+ * Right now we handle:
+ *
+ * - 'M' For a 6-byte MAC address, it prints the address in the
+ * usual colon-separated hex notation
+ * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way (dot-separated
+ * decimal for v4 and colon separated network-order 16 bit hex for v6)
+ * - 'i' [46] for 'raw' IPv4/IPv6 addresses, IPv6 omits the colons, IPv4 is
+ * currently the same
+ *
+ * Note: The difference between 'S' and 'F' is that on ia64 and ppc64
+ * function pointers are really function descriptors, which contain a
+ * pointer to the real address.
+ */
+static char *pointer(const char *fmt, char *buf, void *ptr, int field_width, int precision, int flags)
+{
+ if (!ptr)
+ return string(buf, "(null)", field_width, precision, flags);
+
+#ifdef CONFIG_CMD_NET
+ switch (*fmt) {
+ case 'm':
+ flags |= SPECIAL;
+ /* Fallthrough */
+ case 'M':
+ return mac_address_string(buf, ptr, field_width, precision, flags);
+ case 'i':
+ flags |= SPECIAL;
+ /* Fallthrough */
+ case 'I':
+ if (fmt[1] == '6')
+ return ip6_addr_string(buf, ptr, field_width, precision, flags);
+ if (fmt[1] == '4')
+ return ip4_addr_string(buf, ptr, field_width, precision, flags);
+ flags &= ~SPECIAL;
+ break;
+ }
+#endif
+ flags |= SMALL;
+ if (field_width == -1) {
+ field_width = 2*sizeof(void *);
+ flags |= ZEROPAD;
+ }
+ return number(buf, (unsigned long) ptr, 16, field_width, precision, flags);
+}
+
+/**
+ * vsprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * This function follows C99 vsprintf, but has some extensions:
+ * %pS output the name of a text symbol
+ * %pF output the name of a function pointer
+ * %pR output the address range in a struct resource
+ *
+ * The function returns the number of characters written
+ * into @buf.
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want sprintf() instead.
+ */
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+ unsigned NUM_TYPE num;
+ int base;
+ char *str;
int flags; /* flags to number() */
int field_width; /* width of output field */
int precision; /* min. # of digits for integers; max
number of chars for from string */
- int qualifier; /* 'h', 'l', or 'q' for integer fields */
+ int qualifier; /* 'h', 'l', or 'L' for integer fields */
+ /* 'z' support added 23/7/1999 S.H. */
+ /* 'z' changed to 'Z' --davidm 1/25/99 */
+ /* 't' added for ptrdiff_t */
+
+ str = buf;
- for (str=buf ; *fmt ; ++fmt) {
+ for (; *fmt ; ++fmt) {
if (*fmt != '%') {
*str++ = *fmt;
continue;
@@ -252,7 +520,7 @@ int vsprintf(char *buf, const char *fmt, va_list args)
case ' ': flags |= SPACE; goto repeat;
case '#': flags |= SPECIAL; goto repeat;
case '0': flags |= ZEROPAD; goto repeat;
- }
+ }
/* get field width */
field_width = -1;
@@ -286,14 +554,13 @@ int vsprintf(char *buf, const char *fmt, va_list args)
/* get the conversion qualifier */
qualifier = -1;
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
- *fmt == 'Z' || *fmt == 'z' || *fmt == 't' ||
- *fmt == 'q' ) {
+ *fmt == 'Z' || *fmt == 'z' || *fmt == 't') {
qualifier = *fmt;
- if (qualifier == 'l' && *(fmt+1) == 'l') {
- qualifier = 'q';
+ ++fmt;
+ if (qualifier == 'l' && *fmt == 'l') {
+ qualifier = 'L';
++fmt;
}
- ++fmt;
}
/* default base */
@@ -310,32 +577,18 @@ int vsprintf(char *buf, const char *fmt, va_list args)
continue;
case 's':
- s = va_arg(args, char *);
- if (!s)
- s = "<NULL>";
-
- len = strnlen(s, precision);
-
- if (!(flags & LEFT))
- while (len < field_width--)
- *str++ = ' ';
- for (i = 0; i < len; ++i)
- *str++ = *s++;
- while (len < field_width--)
- *str++ = ' ';
+ str = string(str, va_arg(args, char *), field_width, precision, flags);
continue;
case 'p':
- if (field_width == -1) {
- field_width = 2*sizeof(void *);
- flags |= ZEROPAD;
- }
- str = number(str,
- (unsigned long) va_arg(args, void *), 16,
- field_width, precision, flags);
+ str = pointer(fmt+1, str,
+ va_arg(args, void *),
+ field_width, precision, flags);
+ /* Skip all alphanumeric pointer suffixes */
+ while (isalnum(fmt[1]))
+ fmt++;
continue;
-
case 'n':
if (qualifier == 'l') {
long * ip = va_arg(args, long *);
@@ -355,9 +608,9 @@ int vsprintf(char *buf, const char *fmt, va_list args)
base = 8;
break;
- case 'X':
- flags |= LARGE;
case 'x':
+ flags |= SMALL;
+ case 'X':
base = 16;
break;
@@ -376,12 +629,14 @@ int vsprintf(char *buf, const char *fmt, va_list args)
continue;
}
#ifdef CONFIG_SYS_64BIT_VSPRINTF
- if (qualifier == 'q') /* "quad" for 64 bit variables */
+ if (qualifier == 'L') /* "quad" for 64 bit variables */
num = va_arg(args, unsigned long long);
else
#endif
if (qualifier == 'l') {
num = va_arg(args, unsigned long);
+ if (flags & SIGN)
+ num = (signed long) num;
} else if (qualifier == 'Z' || qualifier == 'z') {
num = va_arg(args, size_t);
} else if (qualifier == 't') {
@@ -389,17 +644,29 @@ int vsprintf(char *buf, const char *fmt, va_list args)
} else if (qualifier == 'h') {
num = (unsigned short) va_arg(args, int);
if (flags & SIGN)
- num = (short) num;
- } else if (flags & SIGN)
- num = va_arg(args, int);
- else
+ num = (signed short) num;
+ } else {
num = va_arg(args, unsigned int);
+ if (flags & SIGN)
+ num = (signed int) num;
+ }
str = number(str, num, base, field_width, precision, flags);
}
*str = '\0';
return str-buf;
}
+/**
+ * sprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @fmt: The format string to use
+ * @...: Arguments for the format string
+ *
+ * The function returns the number of characters written
+ * into @buf.
+ *
+ * See the vsprintf() documentation for format string extensions over C99.
+ */
int sprintf(char * buf, const char *fmt, ...)
{
va_list args;
diff --git a/lib_i386/Makefile b/lib_i386/Makefile
index 4fbcd08..ec6f236 100644
--- a/lib_i386/Makefile
+++ b/lib_i386/Makefile
@@ -38,6 +38,10 @@ COBJS-y += realmode.o
COBJS-y += video_bios.o
COBJS-y += video.o
COBJS-y += zimage.o
+COBJS-y += interrupts.o
+COBJS-y += timer.o
+COBJS-$(CONFIG_SYS_PCAT_INTERRUPTS) += pcat_interrupts.o
+COBJS-$(CONFIG_SYS_GENERIC_TIMER) += pcat_timer.o
SRCS := $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
OBJS := $(addprefix $(obj),$(SOBJS-y) $(COBJS-y))
diff --git a/lib_i386/board.c b/lib_i386/board.c
index 1734f86..e18dfa5 100644
--- a/lib_i386/board.c
+++ b/lib_i386/board.c
@@ -225,6 +225,9 @@ void start_i386boot (void)
static bd_t bd_data;
init_fnc_t **init_fnc_ptr;
+#ifndef CONFIG_SKIP_RELOCATE_UBOOT
+ cmd_tbl_t *p;
+#endif
show_boot_progress(0x21);
gd = &gd_data;
@@ -238,6 +241,10 @@ void start_i386boot (void)
gd->baudrate = CONFIG_BAUDRATE;
+#ifndef CONFIG_SKIP_RELOCATE_UBOOT
+ /* Need to set relocation offset here for interrupt initialization */
+ gd->reloc_off = CONFIG_SYS_BL_START_RAM - TEXT_BASE;
+#endif
for (init_fnc_ptr = init_sequence, i=0; *init_fnc_ptr; ++init_fnc_ptr, i++) {
show_boot_progress(0xa130|i);
@@ -247,6 +254,26 @@ void start_i386boot (void)
}
show_boot_progress(0x23);
+#ifndef CONFIG_SKIP_RELOCATE_UBOOT
+ for (p = &__u_boot_cmd_start; p != &__u_boot_cmd_end; p++) {
+ ulong addr;
+ addr = (ulong) (p->cmd) + gd->reloc_off;
+ p->cmd = (int (*)(struct cmd_tbl_s *, int, int, char *[]))addr;
+ addr = (ulong)(p->name) + gd->reloc_off;
+ p->name = (char *)addr;
+
+ if (p->usage != NULL) {
+ addr = (ulong)(p->usage) + gd->reloc_off;
+ p->usage = (char *)addr;
+ }
+ #ifdef CONFIG_SYS_LONGHELP
+ if (p->help != NULL) {
+ addr = (ulong)(p->help) + gd->reloc_off;
+ p->help = (char *)addr;
+ }
+ #endif
+ }
+#endif
/* configure available FLASH banks */
size = flash_init();
display_flash_config(size);
@@ -262,23 +289,6 @@ void start_i386boot (void)
/* IP Address */
bd_data.bi_ip_addr = getenv_IPaddr ("ipaddr");
- /* MAC Address */
- {
- int i;
- ulong reg;
- char *s, *e;
- char tmp[64];
-
- i = getenv_r ("ethaddr", tmp, sizeof (tmp));
- s = (i > 0) ? tmp : NULL;
-
- for (reg = 0; reg < 6; ++reg) {
- bd_data.bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
- }
-
#if defined(CONFIG_PCI)
/*
* Do pci configuration
diff --git a/lib_i386/interrupts.c b/lib_i386/interrupts.c
new file mode 100644
index 0000000..3f3613a
--- /dev/null
+++ b/lib_i386/interrupts.c
@@ -0,0 +1,159 @@
+/*
+ * (C) Copyright 2009
+ * Graeme Russ, graeme.russ@gmail.com
+ *
+ * (C) Copyright 2007
+ * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com
+ *
+ * (C) Copyright 2006
+ * Detlev Zundel, DENX Software Engineering, dzu@denx.de
+ *
+ * (C) Copyright -2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se
+ *
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file contains the high-level API for the interrupt sub-system
+ * of the i386 port of U-Boot. Most of the functionality has been
+ * shamelessly stolen from the leon2 / leon3 ports of U-Boot.
+ * Daniel Hellstrom, Detlev Zundel, Wolfgang Denk and Josh Huber are
+ * credited for the corresponding work on those ports. The original
+ * interrupt handling routines for the i386 port were written by
+ * Daniel Engström
+ */
+
+#include <common.h>
+#include <asm/interrupt.h>
+
+struct irq_action {
+ interrupt_handler_t *handler;
+ void *arg;
+ unsigned int count;
+};
+
+static struct irq_action irq_handlers[CONFIG_SYS_NUM_IRQS] = { {0} };
+static int spurious_irq_cnt = 0;
+static int spurious_irq = 0;
+
+void irq_install_handler(int irq, interrupt_handler_t *handler, void *arg)
+{
+ int status;
+
+ if (irq < 0 || irq >= CONFIG_SYS_NUM_IRQS) {
+ printf("irq_install_handler: bad irq number %d\n", irq);
+ return;
+ }
+
+ if (irq_handlers[irq].handler != NULL)
+ printf("irq_install_handler: 0x%08lx replacing 0x%08lx\n",
+ (ulong) handler + gd->reloc_off,
+ (ulong) irq_handlers[irq].handler);
+
+ status = disable_interrupts ();
+
+ irq_handlers[irq].handler = handler + gd->reloc_off;
+ irq_handlers[irq].arg = arg;
+ irq_handlers[irq].count = 0;
+
+ unmask_irq(irq);
+
+ if (status)
+ enable_interrupts();
+
+ return;
+}
+
+void irq_free_handler(int irq)
+{
+ int status;
+
+ if (irq < 0 || irq >= CONFIG_SYS_NUM_IRQS) {
+ printf("irq_free_handler: bad irq number %d\n", irq);
+ return;
+ }
+
+ status = disable_interrupts ();
+
+ mask_irq(irq);
+
+ irq_handlers[irq].handler = NULL;
+ irq_handlers[irq].arg = NULL;
+
+ if (status)
+ enable_interrupts();
+
+ return;
+}
+
+__isr__ do_irq(int irq)
+{
+ if (irq < 0 || irq >= CONFIG_SYS_NUM_IRQS) {
+ printf("do_irq: bad irq number %d\n", irq);
+ return;
+ }
+
+ if (irq_handlers[irq].handler) {
+ mask_irq(irq);
+
+ irq_handlers[irq].handler(irq_handlers[irq].arg);
+ irq_handlers[irq].count++;
+
+ unmask_irq(irq);
+ specific_eoi(irq);
+
+ } else {
+ if ((irq & 7) != 7) {
+ spurious_irq_cnt++;
+ spurious_irq = irq;
+ }
+ }
+}
+
+#if defined(CONFIG_CMD_IRQ)
+int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ int irq;
+
+ printf("Spurious IRQ: %u, last unknown IRQ: %d\n",
+ spurious_irq_cnt, spurious_irq);
+
+ printf ("Interrupt-Information:\n");
+ printf ("Nr Routine Arg Count\n");
+
+ for (irq = 0; irq <= CONFIG_SYS_NUM_IRQS; irq++) {
+ if (irq_handlers[irq].handler != NULL) {
+ printf ("%02d %08lx %08lx %d\n",
+ irq,
+ (ulong)irq_handlers[irq].handler,
+ (ulong)irq_handlers[irq].arg,
+ irq_handlers[irq].count);
+ }
+ }
+
+ return 0;
+}
+#endif
diff --git a/lib_i386/pcat_interrupts.c b/lib_i386/pcat_interrupts.c
new file mode 100644
index 0000000..f01298e
--- /dev/null
+++ b/lib_i386/pcat_interrupts.c
@@ -0,0 +1,165 @@
+/*
+ * (C) Copyright 2009
+ * Graeme Russ, graeme.russ@gmail.com
+ *
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file provides the interrupt handling functionality for systems
+ * based on the standard PC/AT architecture using two cascaded i8259
+ * Programmable Interrupt Controllers.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/i8259.h>
+#include <asm/ibmpc.h>
+#include <asm/interrupt.h>
+
+#if CONFIG_SYS_NUM_IRQS != 16
+#error "CONFIG_SYS_NUM_IRQS must equal 16 if CONFIG_SYS_NUM_IRQS is defined"
+#endif
+
+DECLARE_INTERRUPT(0);
+DECLARE_INTERRUPT(1);
+DECLARE_INTERRUPT(3);
+DECLARE_INTERRUPT(4);
+DECLARE_INTERRUPT(5);
+DECLARE_INTERRUPT(6);
+DECLARE_INTERRUPT(7);
+DECLARE_INTERRUPT(8);
+DECLARE_INTERRUPT(9);
+DECLARE_INTERRUPT(10);
+DECLARE_INTERRUPT(11);
+DECLARE_INTERRUPT(12);
+DECLARE_INTERRUPT(13);
+DECLARE_INTERRUPT(14);
+DECLARE_INTERRUPT(15);
+
+int interrupt_init(void)
+{
+ u8 i;
+
+ disable_interrupts();
+
+ /* Setup interrupts */
+ set_vector(0x20, irq_0);
+ set_vector(0x21, irq_1);
+ set_vector(0x23, irq_3);
+ set_vector(0x24, irq_4);
+ set_vector(0x25, irq_5);
+ set_vector(0x26, irq_6);
+ set_vector(0x27, irq_7);
+ set_vector(0x28, irq_8);
+ set_vector(0x29, irq_9);
+ set_vector(0x2a, irq_10);
+ set_vector(0x2b, irq_11);
+ set_vector(0x2c, irq_12);
+ set_vector(0x2d, irq_13);
+ set_vector(0x2e, irq_14);
+ set_vector(0x2f, irq_15);
+
+ /* Mask all interrupts */
+ outb(0xff, MASTER_PIC + IMR);
+ outb(0xff, SLAVE_PIC + IMR);
+
+ /* Master PIC */
+ /* Place master PIC interrupts at INT20 */
+ /* ICW3, One slave PIC is present */
+ outb(ICW1_SEL|ICW1_EICW4, MASTER_PIC + ICW1);
+ outb(0x20, MASTER_PIC + ICW2);
+ outb(IR2, MASTER_PIC + ICW3);
+ outb(ICW4_PM, MASTER_PIC + ICW4);
+
+ for (i = 0; i < 8; i++)
+ outb(OCW2_SEOI | i, MASTER_PIC + OCW2);
+
+ /* Slave PIC */
+ /* Place slave PIC interrupts at INT28 */
+ /* Slave ID */
+ outb(ICW1_SEL|ICW1_EICW4, SLAVE_PIC + ICW1);
+ outb(0x28, SLAVE_PIC + ICW2);
+ outb(0x02, SLAVE_PIC + ICW3);
+ outb(ICW4_PM, SLAVE_PIC + ICW4);
+
+ for (i = 0; i < 8; i++)
+ outb(OCW2_SEOI | i, SLAVE_PIC + OCW2);
+
+ /*
+ * Enable cascaded interrupts by unmasking the cascade IRQ pin of
+ * the master PIC
+ */
+ unmask_irq (2);
+
+ enable_interrupts();
+
+ return 0;
+}
+
+void mask_irq(int irq)
+{
+ int imr_port;
+
+ if (irq >= CONFIG_SYS_NUM_IRQS)
+ return;
+
+ if (irq > 7)
+ imr_port = SLAVE_PIC + IMR;
+ else
+ imr_port = MASTER_PIC + IMR;
+
+ outb(inb(imr_port) | (1 << (irq & 7)), imr_port);
+}
+
+void unmask_irq(int irq)
+{
+ int imr_port;
+
+ if (irq >= CONFIG_SYS_NUM_IRQS)
+ return;
+
+ if (irq > 7)
+ imr_port = SLAVE_PIC + IMR;
+ else
+ imr_port = MASTER_PIC + IMR;
+
+ outb(inb(imr_port) & ~(1 << (irq & 7)), imr_port);
+}
+
+void specific_eoi(int irq)
+{
+ if (irq >= CONFIG_SYS_NUM_IRQS)
+ return;
+
+ if (irq > 7) {
+ /*
+ * IRQ is on the slave - Issue a corresponding EOI to the
+ * slave PIC and an EOI for IRQ2 (the cascade interrupt)
+ * on the master PIC
+ */
+ outb(OCW2_SEOI | (irq & 7), SLAVE_PIC + OCW2);
+ irq = SEOI_IR2;
+ }
+
+ outb(OCW2_SEOI | irq, MASTER_PIC + OCW2);
+}
diff --git a/lib_i386/pcat_timer.c b/lib_i386/pcat_timer.c
new file mode 100644
index 0000000..e282f64
--- /dev/null
+++ b/lib_i386/pcat_timer.c
@@ -0,0 +1,102 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/i8254.h>
+#include <asm/ibmpc.h>
+
+#define TIMER0_VALUE 0x04aa /* 1kHz 1.9318MHz / 1000 */
+#define TIMER2_VALUE 0x0a8e /* 440Hz */
+
+int timer_init(void)
+{
+ /* initialize timer 0 and 2
+ *
+ * Timer 0 is used to increment system_tick 1000 times/sec
+ * Timer 1 was used for DRAM refresh in early PC's
+ * Timer 2 is used to drive the speaker
+ * (to stasrt a beep: write 3 to port 0x61,
+ * to stop it again: write 0)
+ */
+ outb (PIT_CMD_CTR0 | PIT_CMD_BOTH | PIT_CMD_MODE2,
+ PIT_BASE + PIT_COMMAND);
+ outb (TIMER0_VALUE & 0xff, PIT_BASE + PIT_T0);
+ outb (TIMER0_VALUE >> 8, PIT_BASE + PIT_T0);
+
+ outb (PIT_CMD_CTR2 | PIT_CMD_BOTH | PIT_CMD_MODE3,
+ PIT_BASE + PIT_COMMAND);
+ outb (TIMER2_VALUE & 0xff, PIT_BASE + PIT_T2);
+ outb (TIMER2_VALUE >> 8, PIT_BASE + PIT_T2);
+
+ irq_install_handler (0, timer_isr, NULL);
+ unmask_irq (0);
+
+ return 0;
+}
+
+static u16 read_pit(void)
+{
+ u8 low;
+
+ outb (PIT_CMD_LATCH, PIT_BASE + PIT_COMMAND);
+ low = inb (PIT_BASE + PIT_T0);
+
+ return ((inb (PIT_BASE + PIT_T0) << 8) | low);
+}
+
+/* this is not very exact */
+void udelay (unsigned long usec)
+{
+ int counter;
+ int wraps;
+
+ if (timer_init_done)
+ {
+ counter = read_pit ();
+ wraps = usec / 1000;
+ usec = usec % 1000;
+
+ usec *= 1194;
+ usec /= 1000;
+ usec += counter;
+
+ while (usec > 1194) {
+ usec -= 1194;
+ wraps++;
+ }
+
+ while (1) {
+ int new_count = read_pit ();
+
+ if (((new_count < usec) && !wraps) || wraps < 0)
+ break;
+
+ if (new_count > counter)
+ wraps--;
+
+ counter = new_count;
+ }
+ }
+
+}
diff --git a/lib_i386/timer.c b/lib_i386/timer.c
new file mode 100644
index 0000000..58a0212
--- /dev/null
+++ b/lib_i386/timer.c
@@ -0,0 +1,107 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/i8254.h>
+#include <asm/ibmpc.h>
+
+struct timer_isr_function {
+ struct timer_isr_function *next;
+ timer_fnc_t *isr_func;
+};
+
+static struct timer_isr_function *first_timer_isr = NULL;
+static volatile unsigned long system_ticks = 0;
+
+/*
+ * register_timer_isr() allows multiple architecture and board specific
+ * functions to be called every millisecond. Keep the execution time of
+ * each function as low as possible
+ */
+int register_timer_isr (timer_fnc_t *isr_func)
+{
+ struct timer_isr_function *new_func;
+ struct timer_isr_function *temp;
+ int flag;
+
+ new_func = malloc(sizeof(struct timer_isr_function));
+
+ if (new_func == NULL)
+ return 1;
+
+ new_func->isr_func = isr_func + gd->reloc_off;
+ new_func->next = NULL;
+
+ /*
+ * Don't allow timer interrupts while the
+ * linked list is being modified
+ */
+ flag = disable_interrupts ();
+
+ if (first_timer_isr == NULL) {
+ first_timer_isr = new_func;
+ } else {
+ temp = first_timer_isr;
+ while (temp->next != NULL)
+ temp = temp->next;
+ temp->next = new_func;
+ }
+
+ if (flag)
+ enable_interrupts ();
+
+ return 0;
+}
+
+/*
+ * timer_isr() MUST be the registered interrupt handler for
+ */
+void timer_isr(void *unused)
+{
+ struct timer_isr_function *temp = first_timer_isr;
+
+ system_ticks++;
+
+ /* Execute each registered function */
+ while (temp != NULL) {
+ temp->isr_func ();
+ temp = temp->next;
+ }
+}
+
+void reset_timer (void)
+{
+ system_ticks = 0;
+}
+
+ulong get_timer (ulong base)
+{
+ return (system_ticks - base);
+}
+
+void set_timer (ulong t)
+{
+ system_ticks = t;
+}
diff --git a/lib_m68k/board.c b/lib_m68k/board.c
index 583ce10..db45b00 100644
--- a/lib_m68k/board.c
+++ b/lib_m68k/board.c
@@ -584,44 +584,6 @@ void board_init_r (gd_t *id, ulong dest_addr)
* where had to use getenv_r(), which can be pretty slow when
* the environment is in EEPROM.
*/
- s = getenv ("ethaddr");
- for (i = 0; i < 6; ++i) {
- bd->bi_enetaddr[i] = s ? simple_strtoul (s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
-#ifdef CONFIG_HAS_ETH1
- /* handle the 2nd ethernet address */
-
- s = getenv ("eth1addr");
- for (i = 0; i < 6; ++i) {
- bd->bi_enet1addr[i] = s ? simple_strtoul (s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
-#endif
-#ifdef CONFIG_HAS_ETH2
- /* handle the 3rd ethernet address */
-
- s = getenv ("eth2addr");
- for (i = 0; i < 6; ++i) {
- bd->bi_enet2addr[i] = s ? simple_strtoul (s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
-#endif
-
-#ifdef CONFIG_HAS_ETH3
- /* handle 4th ethernet address */
- s = getenv("eth3addr");
- for (i = 0; i < 6; ++i) {
- bd->bi_enet3addr[i] = s ? simple_strtoul (s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
-#endif
-
- /* IP Address */
bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
WATCHDOG_RESET ();
diff --git a/lib_microblaze/board.c b/lib_microblaze/board.c
index 30d7641..1a42640 100644
--- a/lib_microblaze/board.c
+++ b/lib_microblaze/board.c
@@ -173,14 +173,6 @@ void board_init (void)
#endif
#if defined(CONFIG_CMD_NET)
- /* board MAC address */
- s = getenv ("ethaddr");
- printf ("MAC:%s\n",s);
- for (i = 0; i < 6; ++i) {
- bd->bi_enetaddr[i] = s ? simple_strtoul (s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
/* IP Address */
bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
eth_init (bd);
diff --git a/lib_mips/board.c b/lib_mips/board.c
index dfe6831..6fc4845 100644
--- a/lib_mips/board.c
+++ b/lib_mips/board.c
@@ -401,14 +401,6 @@ void board_init_r (gd_t *id, ulong dest_addr)
/* relocate environment function pointers etc. */
env_relocate();
- /* board MAC address */
- s = getenv ("ethaddr");
- for (i = 0; i < 6; ++i) {
- bd->bi_enetaddr[i] = s ? simple_strtoul (s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
-
/* IP Address */
bd->bi_ip_addr = getenv_IPaddr("ipaddr");
diff --git a/lib_nios/board.c b/lib_nios/board.c
index 024beb5..63e79ae 100644
--- a/lib_nios/board.c
+++ b/lib_nios/board.c
@@ -151,11 +151,6 @@ void board_init (void)
env_relocate();
bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
- s = getenv ("ethaddr");
- for (i = 0; i < 6; ++i) {
- bd->bi_enetaddr[i] = s ? simple_strtoul (s, &e, 16) : 0;
- if (s) s = (*e) ? e + 1 : e;
- }
WATCHDOG_RESET ();
devices_init();
diff --git a/lib_nios2/board.c b/lib_nios2/board.c
index d759f0f..70fad1b 100644
--- a/lib_nios2/board.c
+++ b/lib_nios2/board.c
@@ -157,11 +157,6 @@ void board_init (void)
env_relocate();
bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
- s = getenv ("ethaddr");
- for (i = 0; i < 6; ++i) {
- bd->bi_enetaddr[i] = s ? simple_strtoul (s, &e, 16) : 0;
- if (s) s = (*e) ? e + 1 : e;
- }
WATCHDOG_RESET ();
devices_init();
diff --git a/lib_ppc/board.c b/lib_ppc/board.c
index f69c5f4..3b93e4e 100644
--- a/lib_ppc/board.c
+++ b/lib_ppc/board.c
@@ -645,9 +645,8 @@ void board_init_f (ulong bootflag)
void board_init_r (gd_t *id, ulong dest_addr)
{
cmd_tbl_t *cmdtp;
- char *s, *e;
+ char *s;
bd_t *bd;
- int i;
extern void malloc_bin_reloc (void);
#ifndef CONFIG_ENV_IS_NOWHERE
extern char * env_name_spec;
@@ -878,20 +877,6 @@ void board_init_r (gd_t *id, ulong dest_addr)
mac_read_from_eeprom();
#endif
- s = getenv ("ethaddr");
-#if defined (CONFIG_MBX) || \
- defined (CONFIG_RPXCLASSIC) || \
- defined(CONFIG_IAD210) || \
- defined(CONFIG_V38B)
- if (s == NULL)
- board_get_enetaddr (bd->bi_enetaddr);
- else
-#endif
- for (i = 0; i < 6; ++i) {
- bd->bi_enetaddr[i] = s ? simple_strtoul (s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
#ifdef CONFIG_HERMES
if ((gd->board_type >> 16) == 2)
bd->bi_ethspeed = gd->board_type & 0xFFFF;
@@ -899,88 +884,26 @@ void board_init_r (gd_t *id, ulong dest_addr)
bd->bi_ethspeed = 0xFFFF;
#endif
-#ifdef CONFIG_NX823
- load_sernum_ethaddr ();
-#endif
-
+#ifdef CONFIG_CMD_NET
+ /* kept around for legacy kernels only ... ignore the next section */
+ eth_getenv_enetaddr("ethaddr", bd->bi_enetaddr);
#ifdef CONFIG_HAS_ETH1
- /* handle the 2nd ethernet address */
-
- s = getenv ("eth1addr");
-
- for (i = 0; i < 6; ++i) {
- bd->bi_enet1addr[i] = s ? simple_strtoul (s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
+ eth_getenv_enetaddr("eth1addr", bd->bi_enet1addr);
#endif
#ifdef CONFIG_HAS_ETH2
- /* handle the 3rd ethernet address */
-
- s = getenv ("eth2addr");
-#if defined(CONFIG_XPEDITE1K) || defined(CONFIG_METROBOX) || defined(CONFIG_KAREF)
- if (s == NULL)
- board_get_enetaddr(bd->bi_enet2addr);
- else
-#endif
- for (i = 0; i < 6; ++i) {
- bd->bi_enet2addr[i] = s ? simple_strtoul (s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
+ eth_getenv_enetaddr("eth2addr", bd->bi_enet2addr);
#endif
-
#ifdef CONFIG_HAS_ETH3
- /* handle 4th ethernet address */
- s = getenv("eth3addr");
-#if defined(CONFIG_XPEDITE1K) || defined(CONFIG_METROBOX) || defined(CONFIG_KAREF)
- if (s == NULL)
- board_get_enetaddr(bd->bi_enet3addr);
- else
-#endif
- for (i = 0; i < 6; ++i) {
- bd->bi_enet3addr[i] = s ? simple_strtoul (s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
+ eth_getenv_enetaddr("eth3addr", bd->bi_enet3addr);
#endif
-
#ifdef CONFIG_HAS_ETH4
- /* handle 5th ethernet address */
- s = getenv("eth4addr");
-#if defined(CONFIG_XPEDITE1K) || defined(CONFIG_METROBOX) || defined(CONFIG_KAREF)
- if (s == NULL)
- board_get_enetaddr(bd->bi_enet4addr);
- else
+ eth_getenv_enetaddr("eth4addr", bd->bi_enet4addr);
#endif
- for (i = 0; i < 6; ++i) {
- bd->bi_enet4addr[i] = s ? simple_strtoul (s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
-#endif
-
#ifdef CONFIG_HAS_ETH5
- /* handle 6th ethernet address */
- s = getenv("eth5addr");
-#if defined(CONFIG_XPEDITE1K) || defined(CONFIG_METROBOX) || defined(CONFIG_KAREF)
- if (s == NULL)
- board_get_enetaddr(bd->bi_enet5addr);
- else
-#endif
- for (i = 0; i < 6; ++i) {
- bd->bi_enet5addr[i] = s ? simple_strtoul (s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
+ eth_getenv_enetaddr("eth5addr", bd->bi_enet5addr);
#endif
+#endif /* CONFIG_CMD_NET */
-#if defined(CONFIG_TQM8xxL) || defined(CONFIG_TQM8260) || \
- defined(CONFIG_TQM8272) || \
- defined(CONFIG_CCM) || defined(CONFIG_KUP4K) || \
- defined(CONFIG_KUP4X) || defined(CONFIG_PCS440EP)
- load_sernum_ethaddr ();
-#endif
/* IP Address */
bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
diff --git a/lib_sh/board.c b/lib_sh/board.c
index d4cc85c..2fd213b 100644
--- a/lib_sh/board.c
+++ b/lib_sh/board.c
@@ -125,17 +125,7 @@ static int sh_mem_env_init(void)
static int sh_net_init(void)
{
DECLARE_GLOBAL_DATA_PTR;
- char *s, *e;
- int i;
-
gd->bd->bi_ip_addr = getenv_IPaddr("ipaddr");
- s = getenv("ethaddr");
- for (i = 0; i < 6; ++i) {
- gd->bd->bi_enetaddr[i] = s ? simple_strtoul(s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
-
return 0;
}
#endif
diff --git a/lib_sparc/board.c b/lib_sparc/board.c
index e972d3e..2f3e673 100644
--- a/lib_sparc/board.c
+++ b/lib_sparc/board.c
@@ -390,25 +390,6 @@ void board_init_f(ulong bootflag)
board_late_init();
#endif
- s = getenv("ethaddr");
- for (i = 0; i < 6; ++i) {
- bd->bi_enetaddr[i] = s ? simple_strtoul(s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
-
-#ifdef CONFIG_HAS_ETH1
- /* handle the 2nd ethernet address */
-
- s = getenv("eth1addr");
-
- for (i = 0; i < 6; ++i) {
- bd->bi_enet1addr[i] = s ? simple_strtoul(s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
-#endif
-
#ifdef CONFIG_ID_EEPROM
mac_read_from_eeprom();
#endif
diff --git a/nand_spl/board/amcc/acadia/u-boot.lds b/nand_spl/board/amcc/acadia/u-boot.lds
index ab42701..b89cd80 100644
--- a/nand_spl/board/amcc/acadia/u-boot.lds
+++ b/nand_spl/board/amcc/acadia/u-boot.lds
@@ -42,7 +42,7 @@ SECTIONS
.data :
{
- *(.rodata*)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
*(.data*)
*(.sdata*)
__got2_start = .;
diff --git a/nand_spl/board/amcc/bamboo/u-boot.lds b/nand_spl/board/amcc/bamboo/u-boot.lds
index b13168f..d171269 100644
--- a/nand_spl/board/amcc/bamboo/u-boot.lds
+++ b/nand_spl/board/amcc/bamboo/u-boot.lds
@@ -44,7 +44,7 @@ SECTIONS
.data :
{
- *(.rodata*)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
*(.data*)
*(.sdata*)
__got2_start = .;
diff --git a/nand_spl/board/amcc/canyonlands/u-boot.lds b/nand_spl/board/amcc/canyonlands/u-boot.lds
index ef6d560..e676e0c 100644
--- a/nand_spl/board/amcc/canyonlands/u-boot.lds
+++ b/nand_spl/board/amcc/canyonlands/u-boot.lds
@@ -44,7 +44,7 @@ SECTIONS
.data :
{
- *(.rodata*)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
*(.data*)
*(.sdata*)
__got2_start = .;
diff --git a/nand_spl/board/amcc/kilauea/u-boot.lds b/nand_spl/board/amcc/kilauea/u-boot.lds
index 1335532..5a586fc 100644
--- a/nand_spl/board/amcc/kilauea/u-boot.lds
+++ b/nand_spl/board/amcc/kilauea/u-boot.lds
@@ -42,7 +42,7 @@ SECTIONS
.data :
{
- *(.rodata*)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
*(.data*)
*(.sdata*)
__got2_start = .;
diff --git a/nand_spl/board/amcc/sequoia/u-boot.lds b/nand_spl/board/amcc/sequoia/u-boot.lds
index d38d097..1601c36 100644
--- a/nand_spl/board/amcc/sequoia/u-boot.lds
+++ b/nand_spl/board/amcc/sequoia/u-boot.lds
@@ -44,7 +44,7 @@ SECTIONS
.data :
{
- *(.rodata*)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
*(.data*)
*(.sdata*)
__got2_start = .;
diff --git a/nand_spl/board/freescale/mpc8313erdb/u-boot.lds b/nand_spl/board/freescale/mpc8313erdb/u-boot.lds
index 40c4145..ad82589 100644
--- a/nand_spl/board/freescale/mpc8313erdb/u-boot.lds
+++ b/nand_spl/board/freescale/mpc8313erdb/u-boot.lds
@@ -30,8 +30,8 @@ SECTIONS
.text : {
*(.text*)
. = ALIGN(16);
- *(.rodata*)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
. = ALIGN(8);
diff --git a/nand_spl/board/samsung/smdk6400/u-boot.lds b/nand_spl/board/samsung/smdk6400/u-boot.lds
index eb8910c..56e1015 100644
--- a/nand_spl/board/samsung/smdk6400/u-boot.lds
+++ b/nand_spl/board/samsung/smdk6400/u-boot.lds
@@ -42,7 +42,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/nand_spl/board/sheldon/simpc8313/u-boot.lds b/nand_spl/board/sheldon/simpc8313/u-boot.lds
index 40c4145..ad82589 100644
--- a/nand_spl/board/sheldon/simpc8313/u-boot.lds
+++ b/nand_spl/board/sheldon/simpc8313/u-boot.lds
@@ -30,8 +30,8 @@ SECTIONS
.text : {
*(.text*)
. = ALIGN(16);
- *(.rodata*)
*(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
}
. = ALIGN(8);
diff --git a/net/bootp.c b/net/bootp.c
index 83465e4..3dea70aa 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -271,17 +271,11 @@ static void BootpVendorProcess (u8 * ext, int size)
#ifdef DEBUG_BOOTP_EXT
puts ("[BOOTP] Received fields: \n");
- if (NetOurSubnetMask) {
- puts ("NetOurSubnetMask : ");
- print_IPaddr (NetOurSubnetMask);
- putc ('\n');
- }
+ if (NetOurSubnetMask)
+ printf ("NetOurSubnetMask : %pI4\n", &NetOurSubnetMask);
- if (NetOurGatewayIP) {
- puts ("NetOurGatewayIP : ");
- print_IPaddr (NetOurGatewayIP);
- putc ('\n');
- }
+ if (NetOurGatewayIP)
+ printf ("NetOurGatewayIP : %pI4", &NetOurGatewayIP);
if (NetBootFileSize) {
printf ("NetBootFileSize : %d\n", NetBootFileSize);
@@ -579,21 +573,12 @@ BootpRequest (void)
#ifdef CONFIG_BOOTP_RANDOM_DELAY /* Random BOOTP delay */
unsigned char bi_enetaddr[6];
int reg;
- char *e,*s;
- char tmp[64];
ulong tst1, tst2, sum, m_mask, m_value = 0;
if (BootpTry ==0) {
/* get our mac */
- reg = getenv_r ("ethaddr", tmp, sizeof(tmp));
- s = (reg > 0) ? tmp : NULL;
+ eth_getenv_enetaddr("ethaddr", bi_enetaddr);
- for (reg=0; reg<6; ++reg) {
- bi_enetaddr[reg] = s ? simple_strtoul(s, &e, 16) : 0;
- if (s) {
- s = (*e) ? e+1 : e;
- }
- }
#ifdef DEBUG
puts ("BootpRequest => Our Mac: ");
for (reg=0; reg<6; reg++) {
@@ -942,9 +927,7 @@ DhcpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
DhcpOptionsProcess((u8 *)&bp->bp_vend[4], bp);
BootpCopyNetParams(bp); /* Store net params from reply */
dhcp_state = BOUND;
- puts ("DHCP client bound to address ");
- print_IPaddr(NetOurIP);
- putc ('\n');
+ printf ("DHCP client bound to address %pI4\n", &NetOurIP);
/* Obey the 'autoload' setting */
if ((s = getenv("autoload")) != NULL) {
diff --git a/net/eth.c b/net/eth.c
index 217e885..4bbf84b 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -26,6 +26,35 @@
#include <net.h>
#include <miiphy.h>
+#ifdef CONFIG_CMD_NET
+void eth_parse_enetaddr(const char *addr, uchar *enetaddr)
+{
+ char *end;
+ int i;
+
+ for (i = 0; i < 6; ++i) {
+ enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0;
+ if (addr)
+ addr = (*end) ? end + 1 : end;
+ }
+}
+
+int eth_getenv_enetaddr(char *name, uchar *enetaddr)
+{
+ eth_parse_enetaddr(getenv(name), enetaddr);
+ return is_valid_ether_addr(enetaddr);
+}
+
+int eth_setenv_enetaddr(char *name, const uchar *enetaddr)
+{
+ char buf[20];
+
+ sprintf(buf, "%pM", enetaddr);
+
+ return setenv(name, buf);
+}
+#endif
+
#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI)
static char *act = NULL;
@@ -156,8 +185,7 @@ int eth_initialize(bd_t *bis)
{
char enetvar[32];
unsigned char env_enetaddr[6];
- int i, eth_number = 0;
- char *tmp, *end;
+ int eth_number = 0;
eth_devices = NULL;
eth_current = NULL;
@@ -197,13 +225,7 @@ int eth_initialize(bd_t *bis)
}
sprintf(enetvar, eth_number ? "eth%daddr" : "ethaddr", eth_number);
- tmp = getenv (enetvar);
-
- for (i=0; i<6; i++) {
- env_enetaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
- if (tmp)
- tmp = (*end) ? end+1 : end;
- }
+ eth_getenv_enetaddr(enetvar, env_enetaddr);
if (memcmp(env_enetaddr, "\0\0\0\0\0\0", 6)) {
if (memcmp(dev->enetaddr, "\0\0\0\0\0\0", 6) &&
@@ -211,16 +233,10 @@ int eth_initialize(bd_t *bis)
{
printf ("\nWarning: %s MAC addresses don't match:\n",
dev->name);
- printf ("Address in SROM is "
- "%02X:%02X:%02X:%02X:%02X:%02X\n",
- dev->enetaddr[0], dev->enetaddr[1],
- dev->enetaddr[2], dev->enetaddr[3],
- dev->enetaddr[4], dev->enetaddr[5]);
- printf ("Address in environment is "
- "%02X:%02X:%02X:%02X:%02X:%02X\n",
- env_enetaddr[0], env_enetaddr[1],
- env_enetaddr[2], env_enetaddr[3],
- env_enetaddr[4], env_enetaddr[5]);
+ printf ("Address in SROM is %pM\n",
+ dev->enetaddr);
+ printf ("Address in environment is %pM\n",
+ env_enetaddr);
}
memcpy(dev->enetaddr, env_enetaddr, 6);
@@ -249,19 +265,13 @@ int eth_initialize(bd_t *bis)
void eth_set_enetaddr(int num, char *addr) {
struct eth_device *dev;
unsigned char enetaddr[6];
- char *end;
- int i;
debug ("eth_set_enetaddr(num=%d, addr=%s)\n", num, addr);
if (!eth_devices)
return;
- for (i=0; i<6; i++) {
- enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0;
- if (addr)
- addr = (*end) ? end+1 : end;
- }
+ eth_parse_enetaddr(addr, enetaddr);
dev = eth_devices;
while(num-- > 0) {
@@ -272,11 +282,8 @@ void eth_set_enetaddr(int num, char *addr) {
}
debug ( "Setting new HW address on %s\n"
- "New Address is %02X:%02X:%02X:%02X:%02X:%02X\n",
- dev->name,
- enetaddr[0], enetaddr[1],
- enetaddr[2], enetaddr[3],
- enetaddr[4], enetaddr[5]);
+ "New Address is %pM\n",
+ dev->name, enetaddr);
memcpy(dev->enetaddr, enetaddr, 6);
}
diff --git a/net/net.c b/net/net.c
index a55f4d3..a89f6a0 100644
--- a/net/net.c
+++ b/net/net.c
@@ -404,7 +404,7 @@ restart:
#ifdef CONFIG_NET_MULTI
memcpy (NetOurEther, eth_get_dev()->enetaddr, 6);
#else
- memcpy (NetOurEther, bd->bi_enetaddr, 6);
+ eth_getenv_enetaddr("ethaddr", NetOurEther);
#endif
NetState = NETLOOP_CONTINUE;
@@ -709,8 +709,7 @@ NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int len)
}
#ifdef ET_DEBUG
- printf("sending UDP to %08lx/%02x:%02x:%02x:%02x:%02x:%02x\n",
- dest, ether[0], ether[1], ether[2], ether[3], ether[4], ether[5]);
+ printf("sending UDP to %08lx/%pM\n", dest, ether);
#endif
pkt = (uchar *)NetTxPacket;
@@ -931,11 +930,7 @@ int CDPSendTrigger(void)
#ifdef CONFIG_CDP_DEVICE_ID
*s++ = htons(CDP_DEVICE_ID_TLV);
*s++ = htons(CONFIG_CDP_DEVICE_ID);
- memset(buf, 0, sizeof(buf));
- sprintf(buf, CONFIG_CDP_DEVICE_ID_PREFIX "%02X%02X%02X%02X%02X%02X",
- NetOurEther[0] & 0xff, NetOurEther[1] & 0xff,
- NetOurEther[2] & 0xff, NetOurEther[3] & 0xff,
- NetOurEther[4] & 0xff, NetOurEther[5] & 0xff);
+ sprintf(buf, CONFIG_CDP_DEVICE_ID_PREFIX "%pm", NetOurEther);
memcpy((uchar *)s, buf, 16);
s += 16 / 2;
#endif
@@ -1335,10 +1330,8 @@ NetReceive(volatile uchar * inpkt, int len)
if (!NetArpWaitPacketIP || !NetArpWaitPacketMAC)
break;
#ifdef ET_DEBUG
- printf("Got ARP REPLY, set server/gtwy eth addr (%02x:%02x:%02x:%02x:%02x:%02x)\n",
- arp->ar_data[0], arp->ar_data[1],
- arp->ar_data[2], arp->ar_data[3],
- arp->ar_data[4], arp->ar_data[5]);
+ printf("Got ARP REPLY, set server/gtwy eth addr (%pM)\n",
+ arp->ar_data);
#endif
tmp = NetReadIP(&arp->ar_data[6]);
@@ -1461,9 +1454,7 @@ NetReceive(volatile uchar * inpkt, int len)
case ICMP_REDIRECT:
if (icmph->code != ICMP_REDIR_HOST)
return;
- puts (" ICMP Host Redirect to ");
- print_IPaddr(icmph->un.gateway);
- putc(' ');
+ printf (" ICMP Host Redirect to %pI4 ", &icmph->un.gateway);
return;
#if defined(CONFIG_CMD_PING)
case ICMP_ECHO_REPLY:
@@ -1805,15 +1796,6 @@ ushort string_to_VLAN(char *s)
return htons(id);
}
-void print_IPaddr (IPaddr_t x)
-{
- char tmp[16];
-
- ip_to_string (x, tmp);
-
- puts (tmp);
-}
-
IPaddr_t getenv_IPaddr (char *var)
{
return (string_to_ip(getenv(var)));
diff --git a/net/nfs.c b/net/nfs.c
index f290014..0101629 100644
--- a/net/nfs.c
+++ b/net/nfs.c
@@ -741,18 +741,16 @@ NfsStart (void)
printf ("Using %s device\n", eth_get_name());
#endif
- puts ("File transfer via NFS from server "); print_IPaddr (NfsServerIP);
- puts ("; our IP address is "); print_IPaddr (NetOurIP);
+ printf("File transfer via NFS from server %pI4"
+ "; our IP address is %pI4", &NfsServerIP, &NetOurIP);
/* Check if we need to send across this subnet */
if (NetOurGatewayIP && NetOurSubnetMask) {
IPaddr_t OurNet = NetOurIP & NetOurSubnetMask;
IPaddr_t ServerNet = NetServerIP & NetOurSubnetMask;
- if (OurNet != ServerNet) {
- puts ("; sending through gateway ");
- print_IPaddr (NetOurGatewayIP) ;
- }
+ if (OurNet != ServerNet)
+ printf("; sending through gateway %pI4", &NetOurGatewayIP);
}
printf ("\nFilename '%s/%s'.", nfs_path, nfs_filename);
diff --git a/net/tftp.c b/net/tftp.c
index 3dac3d8..b0f1cca 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -508,18 +508,16 @@ TftpStart (void)
#if defined(CONFIG_NET_MULTI)
printf ("Using %s device\n", eth_get_name());
#endif
- puts ("TFTP from server "); print_IPaddr (TftpServerIP);
- puts ("; our IP address is "); print_IPaddr (NetOurIP);
+ printf("TFTP from server %pI4"
+ "; our IP address is %pI4", &TftpServerIP, &NetOurIP);
/* Check if we need to send across this subnet */
if (NetOurGatewayIP && NetOurSubnetMask) {
IPaddr_t OurNet = NetOurIP & NetOurSubnetMask;
IPaddr_t ServerNet = TftpServerIP & NetOurSubnetMask;
- if (OurNet != ServerNet) {
- puts ("; sending through gateway ");
- print_IPaddr (NetOurGatewayIP) ;
- }
+ if (OurNet != ServerNet)
+ printf("; sending through gateway %pI4", &NetOurGatewayIP);
}
putc ('\n');
diff --git a/onenand_ipl/board/apollon/u-boot.onenand.lds b/onenand_ipl/board/apollon/u-boot.onenand.lds
index c8b00a1..0960c12 100644
--- a/onenand_ipl/board/apollon/u-boot.onenand.lds
+++ b/onenand_ipl/board/apollon/u-boot.onenand.lds
@@ -38,7 +38,7 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(.rodata) }
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
diff --git a/post/cpu/mpc8xx/ether.c b/post/cpu/mpc8xx/ether.c
index 5622cb7..fe6c39e 100644
--- a/post/cpu/mpc8xx/ether.c
+++ b/post/cpu/mpc8xx/ether.c
@@ -110,6 +110,7 @@ static RTXBD *rtx;
static void scc_init (int scc_index)
{
bd_t *bd = gd->bd;
+ uchar ea[6];
static int proff[] =
{ PROFF_SCC1, PROFF_SCC2, PROFF_SCC3, PROFF_SCC4 };
@@ -296,11 +297,10 @@ CPM_CR_CH_SCC4 };
pram_ptr->sen_gaddr3 = 0x0; /* Group Address Filter 3 (unused) */
pram_ptr->sen_gaddr4 = 0x0; /* Group Address Filter 4 (unused) */
-#define ea bd->bi_enetaddr
+ eth_getenv_enetaddr("ethaddr", ea);
pram_ptr->sen_paddrh = (ea[5] << 8) + ea[4];
pram_ptr->sen_paddrm = (ea[3] << 8) + ea[2];
pram_ptr->sen_paddrl = (ea[1] << 8) + ea[0];
-#undef ea
pram_ptr->sen_pper = 0x0; /* Persistence (unused) */
pram_ptr->sen_iaddr1 = 0x0; /* Individual Address Filter 1 (unused) */